Looking forward to change

Tag: ActiveRecord

has_many :through, Yes. belongs_to :through, No.

by Daniel Lv on Apr.15, 2009, under Geek

自从Rails出世以来,就提供了has_one,has_many,has_and_belongs_to_many,以及belongs_to这几种典型的模型关联关系。先说has_and_belongs_to_many:

has_and_belongs_to_many是一个好东西,仅用一张中间链表就模拟出了拟双向多对多的关系。而rails并没有就此止步,从rails1.1开始,添加了一个新的关联关系,即has_many :through。他仍然是habtm关系,但是更加优雅,让在后台默默无闻的中间链表从此有了自己的模型,主键,并可以扩充模型方法,用来实现更加优雅的的查询等…我自己一直把他认为是一种高级的habtm,并且尽量使用这种高级habtm,以保持灵活性,方便将来的扩充。

有下面一种场景:

class Shop < ActiveRecord
  belongs_to :city
  belongs_to :country, :through => :city
end

可以实现Shop#country么?答案是不可以。has_many和has_one都有:through了,belongs_to偏偏就没有,为了实现同等效果,我通常写这样的方法:

def country
  city.country
end

有点丑,不是么?这里解释了为什么RailsCore团队迟迟没有添加对belongs_to :through的支持,Rick Olson(来自RailsCore团队)这么说:

 
Because belongs_to is for a foreign key thats in the current table.
If you’re going :through a model, it’s not the same and has_one should
be used.
 

这已经是大概两年半以前的事情了,其实要优雅的处理这种情况很容易,使用ActiveSupport提供的delegate。但是在Rails2.3.2之前。我并不敢大胆这么用,因为如果你的delegate的目标对象不存在的话,调用delegate方法会出”NoMethodError”异常。所以,我被迫这样写:

def country
  city ? city.country : nil
end

好消息是从Rails2.3.2开始为delegate添加了一个新的参数:allow_nil,使得当委托对象不存在时直接返回nil,以后就可以大胆的用了:

delegate :country, :to => :city, :allow_nil => true
1 Comment :, , more...

Looking for something?

Use the form below to search the site:

Still not finding what you're looking for? Drop a comment on a post or contact us so we can take care of it!