When using concerns in Rails controllers how do filters added via before_action operate? Specifically, if I have the following code for which actions in FeedsController will the before_action set_record run? All of them once (show, update, destroy, foobar), all of them once and twice before destroy or only before destroy, foobar (I presume authenticate still runs only before destroy)?
module JsonApiController
extend ActiveSupport::Concern
included do
before_action :authenticate, only %i[ destroy ]
before_action :set_record, only: %i[ show update destroy ]
end
def show/update/destroy
end
protected
def set_record
@record = controller_path.classify.constantize.find(params[:id])
end
end
class FeedsController < ApplicationController
include JsonApiController
before_action :set_record, only: %i[destroy, foobar]
def foobar
...
end
end
I'd like FeedsController to be able to add the set_record filter before any actions it wants without having to know what the JsonApiController did. So, ideally, the filter :set_record would execute once before each of show/update/destroy/foobar but I don't think that's what the code below accomplishes. But more than any particular solution I want to know how before_action works with concerns and included do so I minimize code duplication between concerns and classes.
If this was just inheritance then I know that before_actions are inherited. But this discussion suggests that a before_action in an included do in a module will be overwritten by one in the class but when I try to look at the source it suggests that append_callback is the default action so I'm confused.
From the Rails Guides: Action Controller Overview/Filters:
Calling the same filter multiple times with different options will not work, since the last filter definition will overwrite the previous ones.
That said if you want to change or update the configuration of a before_action
then that new config will override all existing filters with the same method name.
Therefore, in your example, you will need to use the following new declaration to extend (actually override) the existing declaration from the included module:
before_action :set_record, only: %i[show update destroy foobar]