Search code examples
ruby-on-railsrubycallbackspree

Ruby on Rails - Run callback code after initialize method in class


I am using Ruby on Rails 5.2 with ruby 2.4.2p198

Let's say I have a controller (for example this: https://github.com/spree/spree/blob/3-6-stable/backend/app/controllers/spree/admin/reports_controller.rb) and I want to run some code using a callback after the initialize method.

For this, I've created a decorator (for example: reports_controller_decorator.rb) and added the method that I want to run in the after_actioncallback.

My issue is that this works (the method is called) if I use the callback on the index method, but it doesn't work if I pass the initialize method as parameter in the callback:

# It works (note the index method in the callback parameter)
Spree::Admin::ReportsController.class_eval do
  after_action :post_initialize, only: :index

  def post_initialize
    Spree::Admin::ReportsController.add_available_report!(:custom_sales_total)
  end
end
# It doesn't (note the initialize method in the callback parameter)
Spree::Admin::ReportsController.class_eval do
  after_action :post_initialize, only: :initialize

  def post_initialize
    Spree::Admin::ReportsController.add_available_report!(:custom_sales_total)
  end
end

What am I doing wrong? Is possible to run callbacks after the initialize method?


Solution

  • Rails uses the before, after and around _action filters only on "actions". Restfull controllers should only define 7 actions:

    1. show
    2. index
    3. edit
    4. update
    5. new
    6. create
    7. destroy

    Usually controllers don't define an initialize action, although they do inherit an initialize method from their parent class. That is to say there is no route in rails that will go to the initialize method of a controller. Since there is no initialize action to run when you open the index action of Spree::Admin::ReportsController the post_initialize filter is never run.

    Rails has no after_initialize callback for its controllers, only for its models. If you want to add code to the initialize function of the controller you can reopen the class and overwrite the initializer (not recomended) or subclass the controller and call super in the new initializer and add you code afterwords.

    Spree::Admin::ReportsController.class_eval do
      def initialize
        super
        Spree::Admin::ReportsController.add_available_report!(:custom_sales_total)
      end
    end
    

    or

    class CustomSalesTotalController < Spree::Admin::ReportsController
      def initialize
        super
        Spree::Admin::ReportsController.add_available_report!(:custom_sales_total)
      end
    end
    

    Which is actually what Spree is doing under the hood.