Как отмечает @Camway выше, это легко сделать, используя подходящую методологию Rails для СОЕДИНЕНИЯ, ВЫБОРА и ГРУППИРОВАНИЯ. Например, скажем, у меня есть пользователи и регионы, у пользователя может быть от 0 до многих регионов, а у региона может быть от 0 до многих пользователей.
Вот моя область модель:
class Region < ActiveRecord::Base
# attributes: id (integer), code (string)
has_and_belongs_to_many :users
end
Вот мой Пользователь Модель:
class User < ActiveRecord::Base
# attributes: id (integer), email (string)
has_and_belongs_to_many :regions
end
Конечно, есть также таблица соединений region_users с целочисленными полями region_id и user_id.
Чтобы заставить работать универсальную GROUP_CONCAT, которая извлекает коды всех областей, к которым присоединен каждый пользователь, мне просто нужно добавить метод класса, подобный этому, в модель User:
class User < ActiveRecord::Base
# attributes: id (integer), email (string)
has_and_belongs_to_many :regions
class << self
def regions_listing
joins(:regions)
.select("DISTINCT users.email, GROUP_CONCAT(DISTINCT regions.region_code ORDER BY regions.region_code) AS regions_list")
.group("users.email")
.order("users.email")
end
end
end
Итак, имея только этот бит кода, следующий пользователь извлекает все запросы, упорядоченные по адресу электронной почты.
ruby > User.regions_listing
=> [#<User email: "joe@blow.com">,#<User email: "sally@mae.com">,#<User email: "billy@bob.com">,#<User email: "jane@doe.com">,#<User email: "big@ed.com">]
Каждый из этих возвращаемых объектов имеет средство чтения атрибутов # region_list , которое предоставит вам объединенный в группу список кодов для регионов, прикрепленных к этому пользователю через таблицу region_users.
Это можно увидеть с помощью простого вызова #map:
ruby > User.regions_listing.map { |u| [u.email, u.regions_list] }
=> [["joe@blow.com", "0,1,2,3,4,5"], ["sally@mae.com", "1,2,5"], ["billy@bob.com", "0,4"], ["jane@doe.com", "3"], ["big@ed.com", "2,3,4,5"]]
Обратите внимание, что поскольку здесь используются соответствующие AR-методы с поддержкой AREL, он цепочечный . Таким образом, вы можете добавить ". Region_listing" в конце практически любого AR-запроса к модели User, и он даст вам метод / данные, объединенные в группу для любых объектов User, выбранных вашим запросом. .
Как таковой:
ruby > User.where("users.email like 'b%'").regions_listing.map { |u| [u.email, u.regions_list] }
=> [["billy@bob.com", "0,4"], ["big@ed.com", "2,3,4,5"]]
И вы также можете получить данные в вашем производственном поле #regions_list, используя HAVING, например, чтобы найти всех пользователей, подключенных к региону 0 и региону 4:
ruby > User.regions_listing.having("regions_list LIKE '%0%4%'").map { |u| [u.email, u.regions_list] }
=> [["joe@blow.com", "0,1,2,3,4,5"], ["billy@bob.com", "0,4"]]