按关联模型中的列对Rails数据库表进行排序

时间:2011-01-11 22:22:06

标签: mysql ruby-on-rails sorting associations named-scope

我正在尝试实现Ryan Bates的可排序表列代码(Railscast#228),但我希望能够对相关列进行排序。特别是,我有以下模型和协会:

class Project < ActiveRecord::Base
  belongs_to :program_manager, :class_name => "User"

class User < ActiveRecord::Base
  has_many :program_manager_projects, :class_name => "Project", :foreign_key => "program_manager_id"

Project模型和User模型之间的关联由'program_manager_id'外键调解,用户使用collection-select下拉列表在new / edit视图中设置该外键。这是project.rb顶部注释的一部分:

# Table name: projects
# program_manager_id :integer

我希望能够通过程序管理员的名称对索引视图中的项目列表进行排序,即通过project.program_manager.name。

理想情况下,我可以指出:以某种方式命令这个名字,也许在我的ProjectsController的索引方法中有这样的东西:

@projects = Project.find(:all, :order => project.program_manager.name)

但这显然不起作用(更不用说Ryan的例程通过特定引用要排序的模型中的表名来实现它。)

我遇到过一些使用named_scope的令人生畏的方法,例如:

named_scope :most_active, :select => "questions.*", :joins => "left join comments as comments_for_count on comments_for_count.question.id = questions.id", :group => "questions.id", :order => "count(questions.id) desc"

但鉴于我缺乏MySQL的专业知识,这对我来说是相当难以理解的。

任何人都可以帮助我根据我的具体情况概括上面的named_scope示例,还是指出一个更简单的策略?

非常感谢,

迪安

1 个答案:

答案 0 :(得分:4)

让我们剖析您在上面引用的命名范围。想象一下模型问题有很多评论。

named_scope :most_active, :select => "questions.*", :joins => "left join comments as comments_for_count on comments_for_count.question.id = questions.id", :group => "questions.id", :order => "count(questions.id) desc"

:most_active

您的范围名称。你会这样参考:Question.find(:all).most_active

:select => "questions.*"

默认情况下,范围会选择表中的所有列,因此这会将结果仅限于问题表,而不是注释表。这是可选的。

:joins => "left join comments as comments_for_count on comments_for_count.question.id = questions.id"

这是对每个问题的说法,我也想得到与他们相关的所有评论。评论表有一个'question_id'列,我们将使用它来匹配它们到相应的问题记录。这个很重要。它允许我们访问不在我们模型上的字段!

 :group => "questions.id"

这是order子句中count()函数所必需的,告诉我们我们想要基于问题的评论计数。我们的order子句中不需要count函数,所以我们也不需要这个组语句

:order => "count(questions.id) desc"

按照评论数量的顺序返回结果,从最高到最低。

因此,对于我们的例子,放弃我们不需要的东西,并满足您的需求,我们最终得到:

:named_scope :by_program_manager_name, :joins => "left join users on projects.program_manager_id = users.id", :order => "users.name"

这个named_scope将被调用:

Project.find(:all).by_program_manager_name

注意这基本上相当于:

Project.find(:all, :joins => "left join users on projects.program_manager_id = users.id", :order => "users.name")

但是,正如上面提到的cam,你应该真正了解底层的SQL。没有这种理解,你的能力将受到严重阻碍