2012-03-14 33 views
2

模型 “一”如何避免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回调时互相改变?

+0

你究竟想在这里实现什么? – 2012-03-14 14:23:30

+2

即使你有设计上的问题,即使你会解决当前的问题,这也会导致你到下一个问题 – megas 2012-03-14 14:44:37

+0

+1,即使这看起来像设计上的缺陷我已经在这种类型的_cycle中多次发现我的自己回调引用hell_。可以帮助有可能[避免回调adhoc](http://stackoverflow.com/questions/632742/how-can-i-avoid-running-activerecord-callbacks) – fguillen 2012-03-14 14:57:54

回答

2

在希望极少数情况下,您需要这样做,您可能需要使用attr_accessor禁用before_save过滤器或将其移至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 

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

+0

非常聪明..喜欢它! :) – fguillen 2012-03-14 14:59:44

1

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