How can I send a parameter to a before filter?

后端 未结 5 1938
伪装坚强ぢ
伪装坚强ぢ 2021-02-08 10:55

I\'d like to create a before_filter method in my application controller like this...

def check_role(role_name)
  unless logged_in_user.has_role? role_name
    fl         


        
相关标签:
5条回答
  • 2021-02-08 11:04

    You should be able to do this with a block:

    before_filter {|controller| controller.check_role('admin') }
    
    0 讨论(0)
  • 2021-02-08 11:21

    I don't believe you can pass parameters to filters. So what I have do in the past is made static methods that pass the parameter to the method that needs the params.

    So I would have something like this:

    def check_role(role_name)
      unless logged_in_user.has_role? role_name
        flash[:notice] = 'Access to that area requires additional privileges.'
        redirect_to :back
      end
    end
    
    def check_admin_role
       check_role('admin')
    end
    
    def check_blah_role
       check_role('blah')
    end
    

    Then in your controller you'd just call

    before_filter :check_admin_role
    

    There is probably some way to implement this with meta-programming but I am still quite a n00b and haven't figured that part out yet ;)

    0 讨论(0)
  • 2021-02-08 11:22

    You can use a bit of meta-programming. Something like this (completely untested, just something to give you an idea of how it might go):

    Module RoleWithIt
      Role.all.each do |role|
        define_method("check_#{role.name}_role".to_sym) do
          check_role(role.name)
        end
      end
    
      def check_role(role_name)
        return if logged_in_user.has_role?(role_name)
        flash[:notice] = 'Access to that area requires additional privileges.'
        redirect_to :back
      end
    end
    
    ApplicationController.send :include, RoleWithIt
    

    To have it load when your app initialises, just put it in a file called role_with_it.rb and put it in your lib directory.

    0 讨论(0)
  • 2021-02-08 11:27

    am I trying to drive a screw with a hammer?

    Er, possibly ;-)

    If I'm reading this correctly, you have a situation where actions within a controller have different access levels, so you want to remove the duplication by creating a single check function?

    So you're looking to do something like this?

    before_filter :check_role('admin'), :only => [:admin, :debug]
    before_filter :check_role('power'), :only => [:edit, :delete]
    

    But the parameter in parens thing is not legal. And anyway, I still see a fair bit of duplication here!

    In general, with an area of functionality as well-visited as controller filters, if you can't do something, it's probably because you're looking at something the wrong way. (Remember that Rails is proud to describe itself as "opinionated software"!)

    How would it be if you were able to know the action name in your filter method?

    Then we'd have

    before_filter :check_role
    

    Which is pretty DRY.

    We could define permissions in a Hash, perhaps:

    Perms = { :admin => ['admin'], :edit => ['admin', 'power'], etc
    

    ... which seem to encapsulate the distinct elements of the duplication. If it got complex then the whole thing could move off into a table, although then you're probably duplicating functionality already available in a plugin.

    And we'd have

    protected
    def check_role
      for required_role in Perms[params[:action]]
        return if logged_in_user.has_role? required_role
      end
      flash[:notice] = 'Access to that area requires additional privileges.'
      redirect_to :back
    end
    

    Or something similar. params[:action] works on my current Rails version (2.1.2), although the Rails book (v2) mentions an action_name method that seems to return blank for me.

    0 讨论(0)
  • 2021-02-08 11:28

    it's an old question, but if somebody still wonders, a good asnwer for rails 4 can be found here

    0 讨论(0)
提交回复
热议问题