尝试对包含在 activerecord 中的结果进行排序

rob*_*ill 5 activerecord ruby-on-rails

我有一个多次加入另一个模型的 activerecord 模型:

class Claim < ActiveRecord::Base
  belongs_to :user
  belongs_to :treated_by, foreign_key: :treated_by_id, class_name: 'User'
  belongs_to :person_involved, foreign_key: :person_involved_id, class_name: 'User'
  belongs_to :case_manager, foreign_key: :case_manager_id, class_name: 'User'
end
Run Code Online (Sandbox Code Playgroud)

在某些时候,我希望获取 Claims 及其所有 User 实例,因此我通过使用包含来避免 N+1 查询:

claims = Claim.all.includes(:user, :treated_by, :person_involved)
Run Code Online (Sandbox Code Playgroud)

这很好,但现在我想对声明进行排序(没有它们在内存中)所以我想做一些类似的事情:

Claim.all.includes(:user, :person_involved, :treated_by).order('treated_by.last_name')
Run Code Online (Sandbox Code Playgroud)

但是除非我像这样使用表名,否则我会得到无效的 SQL:

Claim.all.includes(:user, :person_involved, :treated_by).order('users.last_name')
Run Code Online (Sandbox Code Playgroud)

例如,这显然不会帮助我通过用户 last_name 的子集处理来订购。我该如何正确地做到这一点?

Fro*_*ost 1

正如Abishek Kumar在他的回答中提到的,您可能应该使用joins而不是includes,因为includes它只是为了防止 N+1 查询问题。它似乎也允许您按关联排序,但如果您的关联具有自定义名称,它不会对您有帮助。

我认为您将不得不暂时离开 ActiveRecord 美好而舒适的地方,并手动编写 join 语句:

Claim.all
  .joins("INNER JOIN users AS treated_bys ON claims.treated_by_id = treated_bys.id")
  .order("treated_bys.last_name ASC")
Run Code Online (Sandbox Code Playgroud)

includes...然后,如果您需要避免 N+1 查询等,您也可以使用语句来补充查询。

  • 好答案!只是想提一下“INNER JOIN users AS treat_bys ON ...”将把“claims”集合限制为那些具有“treatment_by”关联值的集合。没有“treated_by”的声明将不会从数据库中获取。也许使用 LEFT JOIN 会更安全。http://www.w3schools.com/sql/sql_join_left.asp (2认同)