Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using the after_save callback to modify the same object without triggering the callback again (recursion)

If I add an after_save callback to an ActiveRecord model, and on that callback I use update_attribute to change the object, the callback is called again, and so a 'stack overflow' occurs (hehe, couldn't resist).

Is it possible to avoid this behavior, maybe disabling the callback during it's execution? Or is there another approach?

Thanks!

like image 813
Ivan Avatar asked Oct 19 '08 02:10

Ivan


3 Answers

One workaround is to set a variable in the class, and check its value in the after_save.

  1. Check it first. (if var)
  2. Assign it to a 'false' value before calling update_attribute.
  3. call update_attribute.
  4. Assign it to a 'true' value.
  5. end

This way, it'll only attempt to save twice. This will likely hit your database twice, which may or may not be desirable.

I have a vague feeling that there's something built in, but this is a fairly foolproof way to prevent a specific point of recursion in just about any application. I would also recommend looking at the code again, as it's likely that whatever you're doing in the after_save should be done in before_save. There are times that this isn't true, but they're fairly rare.

like image 95
Groxx Avatar answered Oct 17 '22 15:10

Groxx


Could you use the before_save callback instead?

like image 34
srboisvert Avatar answered Oct 17 '22 15:10

srboisvert


I didn't see this answer, so I thought I'd add it in case it helps anyone searching on this topic. (ScottD's without_callbacks suggestion is close.)

ActiveRecord provides update_without_callbacks for this situation, but it is a private method. Use send to get access to it anyway. Being inside a callback for the object you are saving is exactly the reason to use this.

Also there is another SO thread here that covers this pretty well: How can I avoid running ActiveRecord callbacks?

like image 10
Walt Jones Avatar answered Oct 17 '22 15:10

Walt Jones