Avertissement obsolète pour Rails 4 has_many avec commande

105
class RelatedList < ActiveRecord::Base
  extend Enumerize

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

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

end

J'ai ce modèle dans mon application rails qui jette un avertissement lorsque j'essaye de créer des enregistrements dans la console.

DEPRECATION AVERTISSEMENT: Les options suivantes de votre déclaration RelatedList.has_many: contents sont obsolètes:: order. Veuillez utiliser un bloc de portée à la place. Par exemple, les éléments suivants: has_many: spam_comments, conditions: {spam: true}, class_name: 'Comment' doit être réécrit comme suit: has_many: spam_comments, -> {where spam: true}, class_name: 'Comment'. (appelé à partir de /Users/shivam/Code/auroville/avorg/app/models/related_list.rb:7)

Il semble que Rails 4 a une nouvelle syntaxe: order à utiliser dans les modèles, mais je n'arrive pas à trouver la documentation dans les guides Rails.

Shankardevy
la source

Réponses:

250

Dans Rails 4, :ordera été obsolète et doit être remplacé par le bloc de portée lambda, comme indiqué dans l'avertissement que vous avez publié dans la question. Un autre point à noter est que ce bloc de portée doit être passé avant toute autre option d'association telle que dependent: :destroy etc.

Essayez ceci:

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

Pour spécifier le sens de la commande, c'est-à-dire soit ascou desccomme @ joshua-coady et @wsprujit l'ont suggéré, utilisez:

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

ou, en utilisant le style de hachage:

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

Référence supplémentaire sur les portées d'enregistrement actives pourhas_many .

vee
la source
3
fonctionne superbe! où puis-je trouver ces informations dans les guides ou les documents? Je n'en trouve pas. Merci.
shankardevy
4
Qu'en est-il si vous avez plus d'une option obsolète, disons oderet include? Ceci: { order(:position), include(:track) }jette une erreur sur la virgule.
kakubei
2
Pour commander asc / desc, utilisez-> { order(name: :asc) }
wspruijt
1
Si pour une raison quelconque, vous voulez juste que la collection soit commandée quelques fois, vous pouvez également faire list.contents.order('position desc')ce qui peut être globalement plus efficace, et pas comme modèle intrusif (dans la réponse votée, la liste connaît un champ de contenu, ici le contrôleur le sait )
Dirty Henry
35

Il m'a fallu un certain temps pour comprendre comment commander et inclure, j'ai finalement trouvé que vous enchaîniez les déclarations de portée ,

has_many :things, -> { includes(:stuff).order("somedate desc") }, class_name: "SomeThing"
sfoop
la source
2
C'était exactement mon problème. Essayer de comprendre comment ordonner une relation has_many par un attribut parent. Je ne savais pas que vous pouviez faire des articles comme celui-ci, puis commander. Merci!
timothyashaw
27

Je pensais juste que j'ajouterais que si vous avez des arguments de hachage d'options, ils doivent aller après le lambda, comme ceci:

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

Il m'a fallu une minute pour comprendre cela moi-même - j'espère que cela aidera quiconque à venir à cette question ayant le même problème.

Wylliam Judd
la source
3
Ceci est également vrai des associations "via" qui pourraient exister sur l'objet -has_many :items, -> { order 'name' }, through: :suppliers
Major Major
0

Cela fonctionne pour moi avec Rails 4 et MongoDB

has_many :discounts, order: :min_amount.asc
Dave
la source
-4

Vous pouvez également placer la orderclause sur le modèle, par exemple:

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

Devient

has_many :options # In class Answer

default_scope { order 'name' } # In class Option

PS: je l'ai ArgumentError: wrong number of arguments (1 for 0)en faisant has_many :things, -> {}.

Dorian
la source
4
N'utilisez pas la portée par défaut. Si vous avez l'habitude de le faire, vous pouvez ajouter à cette méthode magique plus de logique. Il est difficile de passer outre à l'avenir.
Grzegorz Łuszczek