2012-09-26 111 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