为什么我需要重新加载这个子关联?

时间:2013-02-12 17:42:00

标签: ruby-on-rails caching associations rails-activerecord

在连接活动记录关联时我经常遇到一个问题,我希望最终了解导致它的原因(而不仅仅是解决它)。

当通过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

感谢您的帮助。

2 个答案:

答案 0 :(得分:1)

这与您的操作顺序有关。

在第一次测试中,您致电Task.createcreate获取参数并保存到数据库并返回保存后的结果。它对批处理的引用不一定是您在测试范围内处理的同一批处理。

在第二个测试中,您在调用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]中,反之亦然。