Search code examples
ruby-on-railsruby-on-rails-3rubygemsruby-on-rails-plugins

Running before filter in plugin. Is there any other way?


I am writing my first plugin, and in that plugin, I need to run a method for some controller/action pairs. For this plugin the configuration yml looks like this -

track1:
   start_action: "home", "index"
   end_action: "user", "create"

So, in my plugin I will first read above yml file. After that I want to run an action say - first_function as before_filter to home-controller index-action and I would be running second_function as after_filter for user-controller create-action.

But I couldn't figure out how can I write filters for this, which will be declared in plugin and will run for actions specified by user in above yml files.

Please help !


Solution

  • I see two options to reach your goal.

    First approach: declare both the filters inside the ApplicationController and inside the filter check whether the controller_name and action_name match any in your yaml-configuration. If they match, execute it, if not ignore.

    In code that would like

    class ApplicationController
    
      before_filter :start_action_with_check
      after_filter :end_action_with_check
    
      def start_action_with_check
        c_name, a_name = CONFIG['track1']['start_action'].split(', ')
        if c_name == controller_name && a_name == action_name 
          do_start_action
        end
      end
    
      ...
    

    I hope you get the idea.

    Second approach: a clean way to define before_filter is to define them in a module. Normally you would use the self.included method to define the before_filter, but of course, you can define them conditionally. For example:

    class HomeController < ApplicationController
    
      include StartOrEndAction
    
      ...
    end
    

    and in lib/start_or_end_action.rb you write

    module StartOrEndAction
    
      def self.included(base)
        # e.g. for the start-action        
        c_name, a_name CONFIG['track1']['start_action'].split(', ')
        if c_name == controller_name && a_name == action_name 
          base.before_filter :do_start_action
        end
        # and do the same for the after_filter
      end
    
      def do_start_action
        ...
      end
    
      def do_end_action
        ...
      end
    end 
    

    The advantage of the second solution is that the before_filter and after_filter are only defined when needed. The disadvantage is that you will have to include the module into each controller where you could possible configure the before-filter to take place. The first has the advantage that any controller is covered, and you get a little overhead checking the before- and after filter.

    Hope this helps.