Rails и RABL сортируют дочерний элемент по другой модели, к которой он принадлежит

У меня есть 3 модели:

class City < ActiveRecord::Base
  has_many :buildings
end
class Company < ActiveRecord::Base
  has_many :buildings
end
class Building < ActiveRecord::Base
  belongs_to :city
  belongs_to :company
end

Мне нужно показать здание в каждом городе, но отсортировано по их компании так:

city1
  company1
    building1
    building2
  company2
    building3
city2
  company1
    building5
    building6
    building4
  company2
    building7
    building8

Я не могу понять, как сделать запрос или как правильно использовать rabl для создания этой структуры вывода

РЕДАКТИРОВАТЬ:

Вот что я придумал на данный момент:

cities_controlles.rb:

def index
  @cities = City.all
  @companies = Company.includes(:buildings)
end

index.json.rabl:

collection @cities
attributes :id, :name
node :companies do |city|
  @companies.map do |company|
    { id: company.id, name: company.name, buildings:
     company.buildings.map do |building|
       if building.city_id == city.id
         { id: building.id, name: building.name }
       end
     end.compact
   }
  end
end

1 ответ

Есть много способов сделать это в зависимости от того, как следует использовать результат.

Первый способ:

SELECT 
    cities.name, companies.name, buildings.name
FROM
    cities
LEFT JOIN
   companies ON companies.city_id = city.id
LEFT JOIN 
    buildings ON buildings.city_id = city.id
ORDER BY
    cities.name, companies.name, buildings.name

Результатом должно быть что-то вроде этого:

city1 | company1 | building1
city1 | company1 | building2
city1 | company2 | building3
city2 | company1 | building4
city2 | company1 | building5
city2 | company1 | building6
city2 | company2 | building7
city2 | company2 | building7

И вы можете делать все, что вы хотите с этим столом.

Второй способ (использование агрегатной функции для получения списка зданий для города и компании):

SELECT 
    cities.name, companies.name, GROUP_CONCAT(buildings.name)
FROM
    cities
LEFT JOIN
   companies ON companies.city_id = city.id
LEFT JOIN 
    buildings ON buildings.city_id = city.id
ORDER BY
    cities.name, companies.name
GROUP BY
    cities.name, companies.name

Таким образом, Результ должен быть таким:

city1 | company1 | building1, building2
city1 | company2 | building3
city2 | company1 | building4, building5, building6
city2 | company2 | building7, building8

ПРИМЕЧАНИЕ Имя агрегатной функции (GROUP_CONCAT - для MySQL) отличается в СУБД. В Firebird, например, это "LIST"

Другие вопросы по тегам