代码之家  ›  专栏  ›  技术社区  ›  Ethan

如何将参数发送到before筛选器?

  •  10
  • Ethan  · 技术社区  · 15 年前

    我想在我的应用程序控制器中创建一个before-filter方法,如下所示…

    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
    

    然而,它看起来不像过滤器可以接受参数。

    有没有一种方法可以参数化这个调用,或者我是想用锤子来驱动一个螺钉?

    5 回复  |  直到 11 年前
        1
  •  18
  •   Greg Campbell    15 年前

    您应该能够使用一个块执行此操作:

    before_filter {|controller| controller.check_role('admin') }
    
        2
  •  4
  •   Aupajo    15 年前

    您可以使用一些元编程。类似这样的事情(完全未经测试,只是为了让您了解它的发展方向):

    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
    

    要在应用程序初始化时加载它,只需将其放在名为role_with_it.rb的文件中,并将其放在lib目录中。

        3
  •  4
  •   Mike Woodhouse    15 年前

    我是不是想用 锤子?

    呃,可能;-)

    如果我正确地阅读了这篇文章,您会遇到这样的情况:控制器中的操作具有不同的访问级别,所以您想通过创建一个检查函数来消除重复?

    所以你想做这样的事?

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

    但帕伦斯事件中的参数是不合法的。不管怎样,我仍然看到这里有相当多的重复!

    一般来说,如果你不能做点什么,那可能是因为你看问题的方式不对。(请记住,Rails自豪地将自己描述为“独立的软件”!)

    如果您能够知道筛选方法中的操作名称,那会是什么情况?

    然后我们就会拥有

    before_filter :check_role
    

    很漂亮 DRY .

    我们可以在哈希中定义权限,可能是:

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

    …它似乎封装了复制的不同元素。如果它变得复杂,那么整个事情可能会转移到一个表中,尽管这样你可能会复制插件中已经可用的功能。

    我们会拥有

    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
    

    或者类似的东西。参数[:action]适用于我当前的Rails版本(2.1.2),尽管Rails手册(v2)提到 action_name 对我来说似乎返回空白的方法。

        4
  •  3
  •   vrish88    15 年前

    我不相信你能把参数传递给过滤器。所以我过去所做的就是让静态方法将参数传递给需要参数的方法。

    所以我想要这样的东西:

    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
    

    然后在你的控制器里你只要打电话

    before_filter :check_admin_role
    

    可能有一些方法可以通过元编程实现这个功能,但是我仍然是一个很好的N00B,还没有弄清楚这一部分;)

        5
  •  0
  •   Community Reversed Engineer    7 年前

    这是一个古老的问题,但是如果有人仍然想知道,可以找到一个适合Rails 4的电源。 here