问题
Model "One"
class One < ActiveRecord::Base
before_save :do_stuff
private
def do_stuff
two = Two.find(8)
two.field2 = 'Value'
two.save!
end
end
Model "Two"
class Two < ActiveRecord::Base
before_save :do_stuff
private
def do_stuff
one = One.find(7)
one.field2 = 'SomeValue'
one.save!
end
end
Executing:
two = Two.find(1)
two.somefield = 'NewVal'
two.save!
Infinite loop will start. What would be most ruby-on-rails way to implement two models that must change each other on before_save callback?
回答1:
On the hopefully rare occasions you need to do this, you might want to disable your before_save filter using an attr_accessor or move it to an after_save block to avoid looping.
For example:
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
You'd disable the trigger on at least one of them:
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
Things like this are always very ugly, so try and avoid it unless you can think of no other way. If you need it, make sure you've written enough unit tests to ensure it won't lock into an endless loop under some edge cases.
回答2:
Don't call save in before_save: it will trigger an infinite loop. Return true or false instead -- true if whatever you put in the before_save succeeded, false if it failed. Returning false will cancel the save and all other callbacks.
来源:https://stackoverflow.com/questions/9703797/how-to-avoid-activerecord-model-double-saving