views:

288

answers:

4

I'd like to define a before_filter in a controller, but always have it execute last.

I know about append_before_filter, but I'd like to specify this filter in a module, where other classes may also later add other before_filters.

Is there any way to do this?

A: 

I'm not aware of an elegant way to achieve this. However, using a bit of lateral thinking...you could make sure that all your controllers use prepend_before_filter. That way, if your module uses before_filter you'll know that it will always be the last filter because the controllers be always be adding their filters to the beginning of the filter chain.

John Topley
+1  A: 

According to the rails API, the default "before_filter" is an alias for "append_before_filter", which appends filters onto the end of the filter_chain list. I'd say that there is a reasonable assumption that if you order your filters correctly in the controller that they will be executed in order they are listed. As the previous answer suggests there is also a "prepend_before_filter" that ensures that the filter you're adding is at the front of the filter_chain.

+1  A: 

You could override before_filter in your module, or have the self.included callback hook declare an alias_method_chain :before_filter, :final_filter. This is not recommended for code you'd like to be able to port across multiple versions of Rails, or when you will be releasing code to be used in other contexts.

austinfromboston
+1  A: 

Here's a simple module that allows for execution of arbitrary code after the complete set of before_filters. With a little work, you could probably clean this up so that a queue of special after_before_filters were executed here (with appopriate halting behavior, and so on).

module OneLastFilterModule

  def self.included(base)
    base.class_eval do

      def perform_action_without_filters_with_one_last_filter

        #
        # do "final" before_filter work here
        #

        perform_action_without_filters_without_one_last_filter
      end
      alias_method_chain :perform_action_without_filters, :one_last_filter

    end
  end

end

Note that you should be careful about doing this, since controllers themselves may make assumptions about filter ordering based on declaration order.