2012-09-26 76 views
3

假设你有以下型号:轨道3的has_many通过HAS_ONE

class Category < ActiveRecord::Base 
    has_one :current_heat, class_name: 'Heat' 
    has_many :scores, :through => :current_heat 
end 

class Heat < ActiveRecord::Base 
    belongs_to :category 
    has_many :scores 
end 

class Score < ActiveRecord::Base 
    belongs_to :heat 
end 

出人意料的是,当调用Category.first.scores的ActiveRecord产生以下疑问:

SELECT `categories`.* FROM `categories` LIMIT 1 
SELECT * FROM `scores` INNER JOIN `heats` ON `scores`.`heat_id` = `heats`.`id` WHERE `heats`.`category_id` = 1 

上面的查询忽略的Category#current_heat的HAS_ONE性质。我本来期望更多的东西一样:

SELECT `categories`.* FROM `categories` LIMIT 1 
SELECT `heats`.* FROM `heats` WHERE `heats`.`category_id` = 1 LIMIT 1 
SELECT * FROM `scores` WHERE `scores`.`heat_id` = 6 

这是只有当你明确地遍历从根本上HAS_ONE协会与Category.first.current_heat.scores生产。

这是因为如果ActiveRecord的是默默的治疗我的HAS_ONE作为的has_many。有人可以向我解释这种行为吗?有没有一个优雅的解决方法或“正确的方法”来做到这一点?

回答

4

也许你可以删除

has_many :scores, :through => :current_heat 

,而是仅仅代表

delegate :scores, :to => :current_heat 

,将保留您想要的访问方法Category.first.scores。

0

has_one实际上并不存在照看你的数据库以这种方式。如果有多条匹配foreign_key的记录,它不会抛出错误,只会选择第一条记录。它假定你没有错误地添加额外的记录这将打破自己的has_one关系。

总之,它生成的SQL只要有只有一个连接到类别记录是好的。如果不知为何,你已经添加了哪些不应该存在,因为它是一个has_one额外的记录,那么它不会工作,但它不是ActiveRecord的的工作就是告诉你,这已经发生了。通过HAS_ONE得分:

+0

肯定会有每个类别超过一排预赛,但其没关系,因为我已经添加了'default_scope顺序(“created_at DESC”)'来加热,以确保任何我谈论热火奇异时间感觉,这是最近的热度。这样,我就可以灵活地谈论当前和历史上的热度。因此,从某种意义上说,它有两个has_many和has_one,这取决于用例。 – mgadda