在连接活动记录关联时我经常遇到一个问题,我希望最终了解导致它的原因(而不仅仅是解决它)。
当通过parent.children<<将孩子与父母联系起来时,对孩子的引用会正确地更新自己。如果以反向建立关系(如果通过child.parent =),则这不起作用。
为什么会这样?有没有办法使这种关系成为双向的?
我过去曾尝试inverse_of
但没有成功。我希望它,因为我对这里发生的事情不太了解。
示例:
鉴于这些模型:
class Task < ActiveRecord::Base
belongs_to :batch
attr_accessor :state
end
class Batch < ActiveRecord::Base
has_many :tasks
def change_tasks
tasks.each { |x| x.state = "started" }
end
end
为什么第一个规格会失败但第二个规则会失败?我可以先通过吗?出于某种原因,我需要在第一个规范中重新加载,而不是在第二个规范中重新加载。
describe "avoiding reload" do
context "when association established via child.parent=" do
it "updates child references" do
b = Batch.create
t = Task.create(batch: b)
b.change_tasks
b.tasks[0].state.should == "started" # passes
t.state.should == "started" # fails!?
t.reload.state.should == "started" # passes, note the reload
end
end
context "when association established via parent.children<<" do
it "updates child references" do
b = Batch.create
t = Task.create
b.tasks << t
b.change_tasks
b.tasks[0].state.should == "started" # passes
t.state.should == "started" # passes
end
end
end
感谢您的帮助。
答案 0 :(得分:1)
这与您的操作顺序有关。
在第一次测试中,您致电Task.create
。 create
获取参数并保存到数据库并返回保存后的结果。它对批处理的引用不一定是您在测试范围内处理的同一批处理。
在第二个测试中,您在调用create后分配任务。然后立即访问它。因此,相同的任务t是change_tasks
内和t.state.should == "started"
期间的引用。
答案 1 :(得分:1)
简短回答是第一个规范和第二个规范中的对象不同。
在第一个规范中,您有2个不同的对象(尝试检查rails控制台):
t.object_id != b.tasks[0].object_id
虽然两个对象都引用相同的记录,但它们是不同的。您已更改b.tasks[0]
,但t
保持不变,直到重新加载。
在第二个规范中,只有对象:
t.object_id == b.tasks[0].object_id
因此t
的任何更新都会反映在b.tasks[0]
中,反之亦然。