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?
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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With