如何避免ActiveRecord模型双重保存?

时间:2012-03-14 14:22:20

标签: ruby-on-rails activerecord

模特“一”

class One < ActiveRecord::Base
  before_save :do_stuff

  private
    def do_stuff
      two = Two.find(8)
      two.field2 = 'Value'
      two.save!
    end
end

模型“两个”

class Two < ActiveRecord::Base
  before_save :do_stuff

  private
    def do_stuff
      one = One.find(7)
      one.field2 = 'SomeValue'
      one.save!
    end
end

执行:

two = Two.find(1)
two.somefield = 'NewVal'
two.save!

无限循环将开始。什么是ruby-on-rails方式实现两个必须在before_save回调中互相改变的模型?

2 个答案:

答案 0 :(得分:2)

在极少数情况下,您需要执行此操作,您可能希望使用before_save停用attr_accessor过滤器,或将其移至after_save块以避免循环。

例如:

class One < ActiveRecord::Base
  attr_accessor :not_doing_stuff
  before_save :do_stuff,
    :unless => :not_doing_stuff

private
  def do_stuff
    two = Two.find(8)
    two.field2 = 'Value'
    two.save!
  end
end

您至少在其中一个上禁用触发器:

class Two < ActiveRecord::Base
  before_save :do_stuff

private
  def do_stuff
    one = One.find(7)
    one.not_doing_stuff = true
    one.field2 = 'SomeValue'
    one.save!
  end
end

这样的事情总是非常难看,所以尽量避免它,除非你能想到别的办法。如果您需要它,请确保您已经编写了足够的单元测试,以确保在某些边缘情况下它不会锁定无限循环。

答案 1 :(得分:1)

不要在before_save中调用save:它会触发无限循环。返回true或false - 如果你在before_save中输入的内容成功,则返回true,如果失败则返回false。返回false将取消保存和所有其他回调。