4

次のモデルがあるとします。

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.scoresActiveRecord を呼び出すと、次のクエリが生成されます。

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

上記のクエリは、 の has_one の性質を無視していますCategory#current_heat。私はもっ​​と次のようなものを期待していたでしょう:

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

2 に答える 2

5

多分あなたは削除することができます

has_many :scores, :through => :current_heat

代わりに、has_oneを介して:scoresを委任するだけです。

delegate :scores, :to => :current_heat

これにより、目的のアクセス方法Category.first.scoresが保持されます。

于 2012-09-26T18:28:13.717 に答える
0

has_oneこの方法でデータベースを子守するために実際には存在しません。foreign_key に一致するレコードが複数ある場合、エラーはスローされず、最初のレコードが選択されます。has_one自分で関係を壊すような余分なレコードを誤って追加していないことを前提としています。

結論として、生成される sql は、カテゴリに関連付けられたレコードが 1 つだけである限り問題ありません。なんらかの方法で、存在しないはずの余分なレコードを追加した場合、それは機能しhas_oneませんが、これが発生したことを通知するのは activerecord の仕事ではありません。

于 2012-09-26T16:46:36.993 に答える