Rails: Как вы сортируете модель по столбцу в таблице с двумя ассоциациями? - PullRequest
0 голосов
/ 08 сентября 2011

Проблема, с которой я сталкиваюсь, такова: сортируемая модель - это SchoolClass, который имеет студентов, которые, в свою очередь, имеют проекты, и каждый проект имеет дату окончания.Мне нужно отсортировать 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

, чтобы найти последнюю дату окончания проекта для этого класса, а затем извлечь все классы базы данных и отсортировать их этим методом.Конечно, это просто ужасно, правда?Я действительно хотел бы найти способ рельсов, чтобы получить этот порядок (возможно, с областями применения?).Я думал, что-то вроде SchoolClasses.joins(:students).joins(:projects).order('projects.end_date ASC') может сработать, но это приведет к сбою рельсов (и, глядя на это, логика в любом случае неверна, я думаю).

Есть предложения?

1 Ответ

3 голосов
/ 09 сентября 2011

Попробуйте это:

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 имеют следующие атрибуты:

  • id
  • ранее (

Если вам нужны дополнительные атрибуты, вы можете сделать следующее

1) Добавить дополнительные атрибуты в методы group и select

2)Запросите полный объект SchoolClass с помощью id

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")
...