How do I order a has_many through association in Ruby on Rails?

北慕城南 提交于 2019-11-28 22:16:54

Since condition arguments are deprecated in Rails 4, one should use scope blocks:

has_many :users, -> { order 'users.last_name, users.first_name' }, :through => :assignments

Rails 3.x version:

has_many :users, :through => :assignments, :order => 'users.last_name, users.first_name'

UPDATE: This only works in Rails 3.x (maybe before that too). For 4+, see other answers.

The M.G.Palmer's approach works well, however table name is involved. There is a better way to do it:

has_many :users, :through => :assignments, :order => [ :last_name, :first_name ]

Would this work for you?

# User.rb

class User < ActiveRecord::Base
 default_scope :order => 'last_name ASC'
 ...
end

You can define other named scopes for when sorting needs to be different.

http://ryandaigle.com/articles/2008/11/18/what-s-new-in-edge-rails-default-scoping

This works for me (Rails 4.2)

Applying an ordering on the through map is not preserved, aka this is not enough to have the genres ordered:

has_many    :disk_genre_maps,
            -> {order('disk_genre_map.sort_order')},
            :inverse_of => :disk,
            :dependent  => :destroy,
            :autosave   => true


has_many    :genres,    # not sorted like disk_genre_maps
            :through    => :disk_genre_maps,
            :source     => :genre,
            :autosave   => true

So I overwrite this per instance:

def genres  # redefine genres per instance so that the ordering is preserved
    self.disk_genre_maps.map{|dgm|dgm.genre}
end

To make that work for assignments, this should be something like this (untested)

def genres= some_genres
    self.disk_genre_maps = some_genres.map.with_index do |genre, index|
        DiskGenreMap.new(disk:self, genre:genre, sort_order:index)
    end
end
Ricardo Emerson

I am using Rails (5.0.0.1) and could make the sort with this syntax in my model Group that has many users through group_users:

# Associations.
has_many :group_users
has_many :users, -> { order(:name) }, through: :group_users

Adjust the code to your need that will work.

You could also create a new 'sort_order' column on the assignment table, and add a default scope like

default_scope { order('sort_order desc')}

to your assignments model.

has_many :users, -> { order(:last_name, :first_name) }, :through => :assignments, source: 'user'

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!