【问题标题】:Rails: How do you sort a model by a column in a tabel two associations away?Rails:你如何通过两个关联的表中的列对模型进行排序?
【发布时间】:2011-09-08 19:09:17
【问题描述】:

我遇到的问题是这样的:要排序的模型是 SchoolClass,它有_many 个学生,而后者又有_many 个项目,每个项目都有一个 end_date。我需要对 SchoolClasses 进行四种排序:首先按最早项目 end_date 升序和降序排序,其次按最新项目 end_date 升序和降序排序。这有意义吗?

class SchoolClass < ActiveRecord::Base
  has_many :students
end

class Student < ActiveRecord::Base
  has_many :projects
  belongs_to :school_class
end

class Project < ActiveRecord::Base
  belongs_to :student
end

我能想到的唯一方法是非常暴力,并且涉及在 SchoolClass 模型中使用一个方法来返回该实例的最早和最新项目日期,如下所示:

students.collect(&:projects).flatten.select(&:end_date).sort.last

找到该类的最新项目end_date,然后取出数据库的所有类并按该方法对它们进行排序。当然,这很糟糕,对吧?我真的很想找到获取此排序的 rails 方式(可能有范围?)。我认为像SchoolClasses.joins(:students).joins(:projects).order('projects.end_date ASC') 这样的东西可能会起作用,但这会导致轨道崩溃(现在看看它,无论如何我认为逻辑是错误的)。

有什么建议吗?

【问题讨论】:

  • 当然。一个 SchoolClass 有一组通过学生与之关联的项目。 SchoolClass 的最早 end_date 将是属于该 SchoolClass 的 end_dates 集合中最早的 end_date,而最新的 end_date 是其中最晚的 end_date。所以这两个日期可以被认为是 SchoolClass 的虚拟属性,这些是我想要对它们进行排序的值。
  • 想象一下,有三个 SchoolClasses,Class1、Class2、Class3,最早日期和最晚日期是这样的(分别)[1/1/11,1/5/11],[1/2 /11,1/3/11],[1/3/11,1/4/11]。按最早日期升序排序,它们是 Class1、Class2、Class3。按最新日期升序排序,分别为 Class2、Class3、Class1

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


【解决方案1】:

试试这个:

scs = SchoolClass.joins({:students => :projects}).
  select("school_classes.id, 
          MIN(projects.end_date) AS earliest_end_date,
          MAX(projects.end_date) AS latest_end_date").
  group("school_classes.id").
  order("earliest_end_date ASC")

scs 数组中的对象具有以下属性:

  • 身份证
  • earliest_end_date
  • latest_end_date

如果您需要其他属性,您可以执行以下操作

1) 将附加属性添加到 groupselect 方法

2) 使用 id 查询完整的 SchoolClass 对象

3) 重写查询以使用嵌套的 JOIN

scs = SchoolClass.joins(
"JOIN (
   SELECT a.id, 
          MIN(c.end_date) AS earliest_end_date, 
          MAX(c.end_date) AS latest_end_date
    FROM  school_classes a
    JOIN  students b ON b.class_id = a.id
    JOIN  projects c ON c.student_id = b.id
    GROUP BY a.id
 ) d ON d.id = school_classes.id
").select("school_classes.*, 
           d.earliest_end_date AS earliest_end_date, 
           d.latest_end_date AS latest_end_date").
  order("earliest_end_date ASC")

【讨论】:

  • 更新了我的答案看看
猜你喜欢
  • 2021-03-20
  • 1970-01-01
  • 2011-06-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多