How do I automatically sort a has_many relationship in Rails?

前端 未结 5 1193
情书的邮戳
情书的邮戳 2020-12-12 13:02

This seems like a really simple question but I haven\'t seen it answered anywhere.

In rails if you have:

class Article < ActiveRecord::Base 
  has         


        
相关标签:
5条回答
  • 2020-12-12 13:17

    You can specify the sort order for the bare collection with an option on has_many itself:

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

    Or, if you want a simple, non-database method of sorting, use sort_by:

    article.comments.sort_by &:created_at
    

    Collecting this with the ActiveRecord-added methods of ordering:

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

    Your mileage may vary: the performance characteristics of the above solutions will change wildly depending on how you're fetching data in the first place and which Ruby you're using to run your app.

    0 讨论(0)
  • 2020-12-12 13:35

    If you are using Rails 2.3 and want to use the same default ordering for all collections of this object you can use default_scope to order your collection.

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

    Then if you call

    @students = @class.students
    

    They will be ordered as per your default_scope. TBH in a very general sense ordering is the only really good use of default scopes.

    0 讨论(0)
  • 2020-12-12 13:35

    And if you need to pass some additional arguments like dependent: :destroy or whatever, you should append the ones after a lambda, like this:

    class Article < ActiveRecord::Base 
      has_many :comments, -> { order(created_at: :desc) }, dependent: :destroy
    end
    
    0 讨论(0)
  • 2020-12-12 13:36

    You can use ActiveRecord's find method to get your objects and sort them too.

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

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

    0 讨论(0)
  • 2020-12-12 13:40

    As of Rails 4, you would do:

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

    For a has_many :through relationship the argument order matters (it has to be second):

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

    If you will always want to access comments in the same order no matter the context you could also do this via default_scope within Comment like:

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

    However this can be problematic for the reasons discussed in this question.

    Before Rails 4 you could specify order as a key on the relationship, like:

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

    As Jim mentioned you can also use sort_by after you have fetched results although in any result sets of size this will be significantly slower (and use a lot more memory) than doing your ordering through SQL/ActiveRecord.

    If you are doing something where adding a default order is cumbersome for some reason or you want to override your default in certain cases, it is trivial to specify it in the fetching action itself:

    sorted = article.comments.order('created_at').all
    
    0 讨论(0)
提交回复
热议问题