Rails 3 observers can be tricky. You probably already heard a thousand times how to deal with undefined id issue and how transactions are handled, so let’s take a quick example that can be google’d in just a couple of seconds.
class UserObserver < ActiveRecord::Observer
def after_commit(user)
return unless user.send(:transaction_include_action?, :create)
# some code that should be executed only on create, after transaction is committed
end
end
So what’s wrong with this example? Nothing. But let say SuperUser
has_many users
. Some example code:
class SuperUser < ActiveRecord::Base
has_many :users
end
class User < ActiveRecord::Base
attr_accessible :name
validates :name, presence: true, inclusion: { in: %(foo bar)}
end
class UserObserver < ActiveRecord::Observer
def after_commit(user)
return unless user.send(:transaction_include_action?, :create)
raise "#{user.inspect} | Persisted: #{user.persisted?}"
end
end
And try it out:
# obviously we need super user first
SuperUser.first.users.create(name: "boo") # this won't create record, due validation
#<RuntimeError: #<User id: nil, name: "boo", owner_id: 1, created_at: nil, updated_at: nil> | Persisted: false>
=> #<User id: nil, name: "boo", owner_id: 1, created_at: nil, updated_at: nil>
Hell yeah, observer code executed perfectly, even this is not what we would normally expect. I was quite surprised with this behavior, I recommend checking out ActiveRecord::Transactions internals, if I find some time I will write a follow-up to this, cheers.