Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Run Rails controller before_action callback after others

Is there a simple way to append to the before_action list for a controller in rails, such that other before_action callbacks added later will run before and not after my callback?

My use is that I have a concern that other Controllers will include, and I want the controllers that include it to be able to add their own before_action methods but then have one of my methods called after all of those, but still before the actual action.

Since it's a pretty big codebase with a bunch of developers, for usability I don't want every user of this concern to have to do prepend_before_action or to have to remember to include my module after they declare their callbacks instead of at the top of the class.

I'm pretty sure there's no builtin way to do this, and I'm not super familiar with metaprogramming in ruby. But is there some way to hook into the internals of the callback list as the callbacks are running and add a new callback to the end or something?

like image 267
danny Avatar asked Oct 30 '22 14:10

danny


1 Answers

I found a pretty simple solution - looking at the ActiveSupport::Callbacks source, I noticed that the CallbackChain#append_one method which is what is adding the before_action callbacks to the chain is calling a remove_duplicates method every time you add a callback. So I can do the following in my module, overwriting the before_action method:

module MyModule
  extend ActiveSupport::Concern

  included do
    before_action :my_last_callback
  end

  class_methods do
    def before_action(*args, &blk)
      method(:before_action).super_method.call(*args, &blk)
      method(:before_action).super_method.call(:my_last_callback)
    end
  end

  def my_last_callback
    # do stuff after all before_action callbacks
  end
end

Now the child class can add as many before_action callbacks as they like, and they'll maintain their order but my_last_callback always gets called last. (There will now be extra insertions/deletions in the callback chain and now it's probably O(n^2) instead of O(n) in the number of callbacks, but I don't anticipate there ever being enough callbacks to make this an issue).

like image 156
danny Avatar answered Nov 15 '22 06:11

danny