Cela semble être une question très simple mais je ne l’ai pas vue répondre nulle part.
Dans 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 portée nommée fonctionne si vous devez y faire beaucoup référence et que même les gens font ce genre de choses:
@article.comments.sort { |x,y| x.created_at <=> y.created_at }
Mais quelque chose me dit que cela devrait être plus simple. Qu'est-ce que je rate?
Vous pouvez spécifier l'ordre de tri de la collection nue 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 souhaitez une méthode de tri simple, sans base de données, utilisez sort_by :
article.comments.sort_by &:created_at
Collecter ceci avec les méthodes de commande ajoutées à ActiveRecord:
article.comments.find(:all, :order => 'created_at DESC')
article.comments.all(:order => 'created_at DESC')
Votre kilométrage peut varier: les performances des solutions ci-dessus vont changer énormément en fonction du mode de récupération des données et du type de Ruby que vous utilisez pour exécuter votre application.
A 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 une relation has_many :through
l'ordre des arguments est important (il doit être deuxième):
class Article
has_many :comments, -> { order('postables.sort' :desc) },
:through => :postable
end
Si vous souhaitez toujours accéder aux commentaires dans le même ordre, quel que soit 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 pouviez spécifier order
comme clé de la relation, par exemple:
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, bien que, dans tous les ensembles de résultats, cette taille soit considérablement plus lente (et utilise beaucoup plus de mémoire) que si vous commandiez via SQL/ActiveRecord.
Si vous faites quelque chose pour lequel l'ajout d'un ordre par défaut est fastidieux pour une raison quelconque ou si vous souhaitez remplacer votre ordre par défaut dans certains cas, il est simple de le spécifier dans l'action d'extraction elle-même:
sorted = article.comments.order('created_at').all
Si vous utilisez Rails 2.3 et souhaitez utiliser le même ordre par défaut pour toutes les collections de cet objet, 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. Dans un sens très général, TBH est la seule utilisation vraiment efficace des portées par défaut.
Vous pouvez utiliser la méthode de recherche d'ActiveRecord pour obtenir vos objets et les trier aussi.
@article.comments.find(:all, :order => "created_at DESC")
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
Et si vous devez passer des arguments supplémentaires tels que dependent: :destroy
ou autre, vous devez les ajouter après un lambda, comme ceci:
class Article < ActiveRecord::Base
has_many :comments, -> { order(created_at: :desc) }, dependent: :destroy
end