如何在 Ruby on Rails 中通过关联订购 has_many?
Posted
技术标签:
【中文标题】如何在 Ruby on Rails 中通过关联订购 has_many?【英文标题】:How do I order a has_many through association in Ruby on Rails? 【发布时间】:2011-01-13 10:04:20 【问题描述】:鉴于以下 AR 模型,当给定任务句柄时,我想按姓氏字母顺序对用户进行排序:
#user
has_many :assignments
has_many :tasks, :through => :assignments
#assignment
belongs_to :task
belongs_to :user
#task
has_many :assignments
has_many :users, :through => :assignments
我想获得一项任务,然后导航到其分配的用户,并按字母顺序对用户列表进行排序。
我一直在想我应该能够像这样将:order
子句添加到has_many :users, :through => :assignments
:
#task.rb
has_many :assignments
has_many :users, :through => :assignments, :order => 'last_name, first_name'
但是这不起作用。
当给定任务时,如何按last_name
对用户进行排序?
【问题讨论】:
【参考方案1】:has_many :users, -> order(:last_name, :first_name) , :through => :assignments, source: 'user'
【讨论】:
【参考方案2】:我正在使用 Rails (5.0.0.1),并且可以在我的模型组中使用此语法进行排序,该组通过 group_users 拥有许多用户:
# Associations.
has_many :group_users
has_many :users, -> order(:name) , through: :group_users
根据您的需要调整代码。
【讨论】:
【参考方案3】:Rails 3.x 版本:
has_many :users, :through => :assignments, :order => 'users.last_name, users.first_name'
更新:这只适用于 Rails 3.x(可能在此之前)。对于 4+,请参阅其他答案。
【讨论】:
对我也很好。干净的解决方案,不会像第一个答案那样影响排序模型的其他功能。 不工作,它说:order is not a key。以下拒绝的答案是有效的。【参考方案4】:这对我有用(Rails 4.2)
在直通地图上应用排序不会被保留,也就是说,这不足以对流派进行排序:
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
所以我每个实例都覆盖这个:
def genres # redefine genres per instance so that the ordering is preserved
self.disk_genre_maps.map|dgm|dgm.genre
end
为了使这项工作适用于分配,这应该是这样的(未经测试)
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
【讨论】:
【参考方案5】:由于 Rails 4 不推荐使用条件参数,因此应该使用范围块:
has_many :users, -> order 'users.last_name, users.first_name' , :through => :assignments
【讨论】:
目前在 Rails 4 中似乎存在一个错误,github.com/rails/rails/issues/17904 "在 Rails 4.0 中,order 子句被忽略。在 Rails 4.1 中,生成了无效的 SQL。" 它甚至没有给我,只是完全忽略了没有消息的订单子句。【参考方案6】:您还可以在分配表上创建一个新的“排序顺序”列,并添加一个默认范围,例如
default_scope order('sort_order desc')
到您的分配模型。
【讨论】:
【参考方案7】:M.G.Palmer's
方法效果很好,但是涉及到表名。有更好的方法:
has_many :users, :through => :assignments, :order => [ :last_name, :first_name ]
【讨论】:
但是如果顺序是由连接表决定的呢?例如分配...但没有定义分配的默认范围..【参考方案8】:这对你有用吗?
# User.rb
class User < ActiveRecord::Base
default_scope :order => 'last_name ASC'
...
end
当排序需要不同时,您可以定义其他命名范围。
http://ryandaigle.com/articles/2008/11/18/what-s-new-in-edge-rails-default-scoping
【讨论】:
很抱歉提出一个老问题,但这可能与未来的读者有关:某些插件(例如 acts_as_list)不能与 default_scope 一起正常工作。 也遇到了这个问题,因为我遇到了类似的问题,但需要对 :through 表中的字段进行排序 - 令人敬畏的是 default_scope 也适用于 :through 表,并且通过检索记录这种关系将尊重秩序。 拥有default_scope
是一种非常糟糕的做法。有很多关于这个主题的文章,例如:piechowski.io/post/why-is-default-scope-bad-rails以上是关于如何在 Ruby on Rails 中通过关联订购 has_many?的主要内容,如果未能解决你的问题,请参考以下文章
在 ruby on rails 3 中通过电子邮件创建订阅
如何正确销毁 ruby on rails 中的关联记录?