通过其多态关联的属性对Rails模型进行排序

时间:2014-07-08 23:08:30

标签: ruby-on-rails postgresql polymorphic-associations active-record-query

我想这是一个重复的问题,但我还没有找到它所以我想我会问。我有一个User模型,通过多态关联提供不同类型的Profile模型。类似的东西:

class User < ActiveRecord::Base
  belongs_to :profile, polymorphic: true
end

class Profile < ActiveRecord::Base
  has_one :user, as: :profile
end

class FacebookProfile < ActiveRecord::Base
  has_one :user, as: :profile
end

我想在User上执行一个查询,返回按其个人资料对象的名字排序的用户。在没有任何多态关系之前,我可以通过joins上的:profile开始,但我知道这不适用于多态。

除了使用sortsort_by之外,还有更好的方法吗?

User.all.sort_by {|user| user.profile.first_name }

1 个答案:

答案 0 :(得分:5)

它适用于SQL。

SELECT users.*, COALESCE(profiles.first_name, facebook_profiles.first_name) AS c_first_name FROM users 
LEFT JOIN profiles ON users.profile_id=profiles.id AND users.profile_type="Profile" 
LEFT JOIN facebook_profiles ON users.profile_id=facebook_profiles.id AND users.profile_type="FacebookProfile" 
ORDER BY c_first_name ASC

您应该能够在User模型上使用此“手动”联接创建范围,因为您可以在两列上使用COALESCE来创建可以排序的别名。

尝试这样的事情

class User < ActiveRecord::Base
  belongs_to :profile, polymorphic: true

  scope :sort_by_first_name, -> { select("users.*", "COALESCE(profiles.first_name, facebook_profiles.first_name) AS c_first_name").joins("LEFT JOIN profiles ON users.profile_id=profiles.id AND users.profile_type='Profile'").joins("LEFT JOIN facebook_profiles ON users.profile_id=facebook_profiles.id AND users.profile_type='FacebookProfile'").order("c_first_name ASC") }
end

我自己没有尝试过,但理论上它应该有用。