How to organize complex callbacks in Rails?

callback, ruby-on-rails

Solution

You should be able to rewrite that code -- something like this? Of course your real code probably has some additional complexity -- ALSO: this code is untested.

Class Parent < ActiveRecord::Base
  has_many :children

  # only called when a new record is created
  after_create :first_function 

  # only called for updates, not new records, should still be inside the current transaction
  after_update :last_function

  private
    def first_function
      self.children.create(:name => "Richard The Lion Heart")
      # don't call save in here, already in a transaction
    end

    def last_function
      self.process
      # don't call save in here, already in a transaction        
    end

    def process
      # doing stuff ....
      self.children[0].update_attribute(:name, "Beowulf")
    end
end    

http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html

That’s a total of twelve callbacks, which gives you immense power to react and prepare for each state in the Active Record life cycle. The sequence for calling Base#save for an existing record is similar, except that each _create callback is replaced by the corresponding _update callback.

usage

p = Parent.new(:foo => "bar")
p.save
p.children[0].name
# => "Richard The Lion Heart"

p.update_attributes(:baz => "fud")
p.children[0].name
# => Beowulf

ActiveRecord callbacks from rails console (with awesome_print ap)

> ap ActiveRecord::Callbacks::CALLBACKS
[
  [ 0] :after_initialize,
  [ 1] :after_find,
  [ 2] :after_touch,
  [ 3] :before_validation,
  [ 4] :after_validation,
  [ 5] :before_save,
  [ 6] :around_save,
  [ 7] :after_save,
  [ 8] :before_create,
  [ 9] :around_create,
  [10] :after_create,
  [11] :before_update,
  [12] :around_update,
  [13] :after_update,
  [14] :before_destroy,
  [15] :around_destroy,
  [16] :after_destroy,
  [17] :after_commit,
  [18] :after_rollback
]

Problem

I have a Rails application, that uses callbacks a lot.. so that I have quite a few functions getting called :after_create and :after_commit in multiple models. I wonder if the way I am doing it right now is the best. Basically I have the following scenario: ``` Class Parent < ActiveRecord::Base has_many :children after_create :first_function after_commit :last_function def first_function if !self.processed? self.children.create(:name => "Richard The Lion Heart") self.processed = true self.save! end end def last_function if self.processed? if !self.processing? self.process self.save! self.processing = true self.save! end end end end ``` So you can see the whole thing depends on some strange dual boolean checks because otherwise second_function is getting called every time the model is being updated and it can be updated by the function itself and so the function is getting called repetitively. Overall it leads me to the case where I have to introduce a new boolean check for every callback to fire off. It works but I don't see it as elegant. What am I missing?

Original source