Howto debug: Rails after_commit seems to not get fired?

454 views Asked by At
class Car < ActiveRecord::Base
  has_many :adverts
end

class Advert < ActiveRecord::Base
  belongs_to :car
end

I also have an observer on Advert that looks like this:

class AdvertObserver < ActiveRecord::Observer

  def before_save advert
    @should_update_car_price = advert.price_changed?
    return true #An ActiveRecord::RecordNotSaved will be thrown if return false
  end

  def after_commit advert
    enqueue_car_price_refresh_job_if_necessary(advert)

    reset_async_processing_indicators!
  end

  def reset_async_processing_indicators!
    @should_update_car_price = nil
  end

  #
  # Async processing
  #

  def enqueue_car_price_refresh_job_if_necessary advert
    WorkerJobs::CarPriceRefreshJob.perform_async(advert.car_id) if @should_update_car_price
  end

end

Now, the basic idea is, that I need to make sure that the async_processing of the CarPriceRefreshJob is first enqueued for processing AFTER the advert has been persisted. The problem is though, that it depends if the advert.price has changed or not (dirty) which is not available in an after_commit. This is why I instead set a "flag" in before_save: @should_update_car_price. This seems to work, however there seems to be a few cases in my database where the price on car was NOT synced with the advert (the async job was not run, maybe not enqueued). If I manually enqueue the CarPriceRefreshJob for one of these not updated records, it updates as it should, and hence I'm suspecting the callback rather than the job itself.

As stated I'm suspecting the implementation I made of the callback, but I'm very unsure how I can possible debug it? I made tests for all cases I can think of, and they all pass.

I'm running rails 4 BTW with postgresql 9.3

1

There are 1 answers

0
Cristian On BEST ANSWER

Don't use instance variables on Observers. They are singletons and therefore the instance variables persist when observing other objects.

Loading Observers register themselves in the model class they observe, since it is the class that notifies them of events when they occur. As a side-effect, when an observer is loaded its corresponding model class is loaded.

Up to (and including) Rails 2.0.2 observers were instantiated between plugins and application initializers. Now observers are loaded after application initializers, so observed models can make use of extensions.

If by any chance you are using observed models in the initialization you can still load their observers by calling ModelObserver.instance before. Observers are singletons and that call instantiates and registers them.

http://www.rubydoc.info/gems/rails-observers/0.1.2/ActiveRecord/Observer

This should be catched with a test that saves 2 objects one after another in the same spec.