Есть ли идиоматический способ вырезать посредника в объединении в Rails? - PullRequest
2 голосов
/ 22 февраля 2011

У нас есть модель Customer, которая имеет множество отношений has_many, например, в CustomerCountry и CustomerSetting. Часто нам нужно объединить эти отношения друг с другом; например найти настройки клиентов в данной стране. Обычный способ выразить это будет что-то вроде

CustomerSetting.find :all,
                     :joins => {:customer => :customer_country},
                     :conditions => ['customer_countries.code = ?', 'us']

но эквивалентный SQL заканчивается как

SELECT ... FROM customer_settings 
INNER JOIN customers ON customer_settings.customer_id = customers.id
INNER JOIN customer_countries ON customers.id = customer_countries.customer_id

когда я действительно хочу

SELECT ... FROM customer_settings
INNER JOIN countries ON customer_settings.customer_id = customer_countries.customer_id

Я могу сделать это, явно установив: joins SQL, но есть ли идиоматический способ указать это соединение?

1 Ответ

1 голос
/ 22 февраля 2011

Кроме того, мне было немного трудно понять, что у вас есть «страна», принадлежащая ровно одному клиенту:

Почему бы вам просто не добавить еще одну ассоциацию в вашу модель, чтобы каждый параметр has_many customer_countries. Таким образом, вы можете пойти

CustomerSetting.find(:all, :joins => :customer_countries, :conditions => ...)

Если, например, у вас есть отношение 1-1 между клиентом и его настройками, вы также можете выбрать через клиентов:

class Customer
  has_one :customer_setting
  named_scope :by_country, lambda { |country| ... }
  named_scope :with_setting, :include => :custome_setting
  ...
end

, а затем

Customer.by_country('us').with_setting.each do |cust|
  setting = cust.customer_setting
  ...
end

В общем, я считаю гораздо более элегантным использование именованных областей, не говоря уже о том, что области станут методом поиска по умолчанию, а текущий #find API будет устаревшим с будущими версиями Rails.

Кроме того, не слишком беспокойтесь о производительности ваших запросов. Исправляйте только то, что вы на самом деле видите плохо выполняете. (Если у вас действительно есть критический запрос в приложении с высокой нагрузкой, вы, вероятно, в итоге получите #find_by_sql. Но , если это не имеет значения, не оптимизируйте его .

...