开发者

Is there an idiomatic way to cut out the middle-man in a join in Rails?

We have a Customer model, which has a lot of has_many relations, e.g. to CustomerCountry and CustomerSetting. Often, we need to join these relations to each other; e.g. to find the settings of customers in a given country. The normal way of expressing this would be something like

CustomerSetting.find :all,
                     :joins => {:customer => :customer_country},
                     :conditions => ['customer_countries.co开发者_Go百科de = ?', 'us']

but the equivalent SQL ends up as

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

when what I really want is

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

I can do this by explicitly setting the :joins SQL, but is there an idiomatic way to specify this join?


Besides of finding it a bit difficult wrapping my head around the notion that you have a "country" which belongs to exactly one customer:

Why don't you just add another association in your model, so that each setting has_many customer_countries. That way you can go

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

If, for example, you have a 1-1 relationship between a customer and her settings, you could also select through the customers:

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

and then

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

In general, I find it much more elegant to use named scopes, not to speak of that scopes will become the default method for finding, and the current #find API will be deprecated with futures versions of Rails.

Also, don't worry too much about the performance of your queries. Only fix the things that you actually see perform badly. (If you really have a critical query in a high-load application, you'll probably end up with #find_by_sql. But if it doesn't matter, don't optimize it.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜