Comment sortinger automatiquement une relation has_many dans Rails?

Cela semble être une question très simple, mais je n’ai pas vu de réponse nulle part.

En rails si vous avez:

class Article < ActiveRecord::Base has_many :comments end class Comments < ActiveRecord::Base belongs_to :article end 

Pourquoi ne pouvez-vous pas commander les commentaires avec quelque chose comme ceci:

 @article.comments(:order=>"created_at DESC") 

La scope nommée fonctionne si vous avez besoin de la référencer beaucoup et même les gens font des choses comme ceci:

 @article.comments.sort { |x,y| x.created_at  y.created_at } 

Mais quelque chose me dit que ça devrait être plus simple. Qu’est-ce que je rate?

Vous pouvez spécifier l’ordre de sorting de la collection bare avec une option sur has_many lui-même:

 class Article < ActiveRecord::Base has_many :comments, :order => 'created_at DESC' end class Comment < ActiveRecord::Base belongs_to :article end 

Ou, si vous voulez une méthode de sorting simple, sans firebase database, utilisez sort_by :

 article.comments.sort_by &:created_at 

En rassemblant ceci avec les méthodes de commande ajoutées par ActiveRecord:

 article.comments.find(:all, :order => 'created_at DESC') article.comments.all(:order => 'created_at DESC') 

Votre kilométrage peut varier: les caractéristiques de performance des solutions ci-dessus changeront énormément en fonction de la manière dont vous récupérez les données et du Ruby que vous utilisez pour exécuter votre application.

À partir de Rails 4, vous feriez:

 class Article < ActiveRecord::Base has_many :comments, -> { order(created_at: :desc) } end class Comment < ActiveRecord::Base belongs_to :article end 

Pour un has_many :through relation, l’ordre des arguments est important (il faut que ce soit la seconde):

 class Article has_many :comments, -> { order('postables.sort' :desc) }, :through => :postable end 

Si vous voulez toujours accéder aux commentaires dans le même ordre, peu importe le contexte, vous pouvez également le faire via default_scope dans Comment comme:

 class Comment < ActiveRecord::Base belongs_to :article default_scope { order(created_at: :desc) } end 

Cependant, cela peut être problématique pour les raisons évoquées dans cette question .

Avant Rails 4, vous pouvez spécifier l' order comme clé de la relation, comme:

 class Article < ActiveRecord::Base has_many :comments, :order => 'created_at DESC' end 

Comme Jim l'a mentionné, vous pouvez également utiliser sort_by après avoir récupéré les résultats, même si, dans tous les jeux de résultats de taille, cela sera beaucoup plus lent (et utilisera beaucoup plus de mémoire) que votre commande via SQL / ActiveRecord.

Si vous faites quelque chose où append un ordre par défaut est fastidieux pour une raison quelconque ou que vous voulez remplacer votre valeur par défaut dans certains cas, il est sortingvial de le spécifier dans l'action de récupération proprement dite:

 sorted = article.comments.order('created_at').all 

Si vous utilisez Rails 2.3 et que vous souhaitez utiliser le même ordre par défaut pour toutes les collections de cet object, vous pouvez utiliser default_scope pour commander votre collection.

 class Student < ActiveRecord::Base belongs_to :class default_scope :order => 'name' end 

Alors si vous appelez

 @students = @class.students 

Ils seront commandés selon votre default_scope. TBH, dans un sens très général, est la seule bonne utilisation des scopes par défaut.

Vous pouvez utiliser la méthode de recherche d’ActiveRecord pour obtenir vos objects et les sortinger également.

  @article.comments.find(:all, :order => "created_at DESC") 

http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html

Et si vous avez besoin de transmettre des arguments supplémentaires tels que dependent: :destroy ou autre, vous devez append ceux qui suivent un lambda, comme ceci:

 class Article < ActiveRecord::Base has_many :comments, -> { order(created_at: :desc) }, dependent: :destroy end