Устарело предупреждение для Rails 4 has_many с порядком

105
class RelatedList < ActiveRecord::Base
  extend Enumerize

  enumerize :list_type, in: %w(groups projects)

  belongs_to :content
  has_many :contents, :order => :position

end

У меня есть эта модель в моем приложении rails, которое выдает предупреждение, когда я пытаюсь создать записи в консоли.

ПРЕДУПРЕЖДЕНИЕ ОБ УСТАРЕВАНИИ: Следующие параметры в объявлении RelatedList.has_many: contents устарели:: order. Вместо этого используйте блок области видимости. Например, следующее: has_many: spam_comments, условия: {spam: true}, class_name: 'Comment' следует переписать следующим образом: has_many: spam_comments, -> {where spam: true}, class_name: 'Comment'. (вызывается из /Users/shivam/Code/auroville/avorg/app/models/related_list.rb:7)

Похоже, в Rails 4 появился новый синтаксис: order для использования в моделях, но я не могу найти документацию в Rails Guides.

Шанкардевы
источник

Ответы:

250

В Rails 4 :orderон устарел и должен быть заменен блоком области лямбда, как показано в предупреждении, которое вы разместили в вопросе. Также следует отметить, что этот блок области видимости необходимо передать перед любыми другими параметрами ассоциации, такими как dependent: :destroy и т. Д.

Попробуйте:

has_many :contents, -> { order(:position) }

Чтобы указать направление заказа, то есть либо, ascлибо descкак предложили @ joshua-coady и @wsprujit, используйте:

has_many :contents, -> { order 'position desc' }

или, используя стиль хеширования:

has_many :contents, -> { order(position: :desc) }

Дополнительная информация об областях Active Record дляhas_many .

Ви
источник
3
работает превосходно! где я могу найти такую ​​информацию в руководствах или документах? Я не могу найти ни одного. Спасибо.
Шанкардевы
4
Что делать, если у вас есть несколько устаревших вариантов, скажем oderи include? Это: { order(:position), include(:track) }выдает ошибку в запятой.
kakubei
2
Для заказа asc / desc используйте-> { order(name: :asc) }
wspruijt
1
Если по какой-то причине вы просто хотите, чтобы коллекция была заказана несколько раз, вы также можете сделать list.contents.order('position desc')это в целом более эффективно, а не как навязчивую модель (в проголосованном ответе list знает поле контента, здесь контроллер знает это )
Грязный Генри
35

Мне потребовалось некоторое время, чтобы выяснить, как сделать заказ и включить, в конце концов я обнаружил, что вы связываете операторы области действия ,

has_many :things, -> { includes(:stuff).order("somedate desc") }, class_name: "SomeThing"
сфооп
источник
2
Это была моя проблема. Пытаюсь понять, как упорядочить отношения has_many по родительскому атрибуту. Не понимал, что вы можете сделать такие вещи, а затем заказать. Спасибо!
timothyashaw
27

Просто подумал, что я бы добавил, что если у вас есть какие-либо хэш-аргументы, они должны идти после лямбда, например:

has_many :things, -> { order :stuff }, dependent: :destroy

У меня ушла минута, чтобы разобраться в этом сам - надеюсь, это поможет любому, кто подойдет к этому вопросу с той же проблемой.

Уиллиам Джадд
источник
3
Это также верно в отношении "сквозных" ассоциаций, которые могут существовать на объекте -has_many :items, -> { order 'name' }, through: :suppliers
Major Major
0

У меня это работает с Rails 4 и MongoDB

has_many :discounts, order: :min_amount.asc
Дэйв
источник
-4

В качестве альтернативы вы можете поместить orderпредложение в модель, например:

has_many :options, order: 'name' # In class Answer

Становится

has_many :options # In class Answer

default_scope { order 'name' } # In class Option

PS: Получил ArgumentError: wrong number of arguments (1 for 0)когда делаю has_many :things, -> {}.

Дориан
источник
4
Не используйте область по умолчанию. Если вы привыкли это делать, вы можете добавить в этот магический метод больше логики. В будущем это будет сложно преодолеть.
Grzegorz uszczek