Как я могу отправить параметр перед фильтром? - PullRequest
10 голосов
/ 24 марта 2009

Я бы хотел создать метод 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 ]

18 голосов
/ 24 марта 2009

Вы должны быть в состоянии сделать это с блоком:

before_filter {|controller| controller.check_role('admin') }
4 голосов
/ 24 марта 2009

я пытаюсь винт с молоток

Э-э, возможно; -)

Если я правильно читаю, у вас есть ситуация, когда действия в контроллере имеют разные уровни доступа, поэтому вы хотите удалить дублирование, создав одну функцию проверки?

Значит, ты собираешься сделать что-то подобное?

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

Но параметр в скобках недопустим. И в любом случае, я все еще вижу здесь частое дублирование!

В общем, с областью функциональности, которая так же часто посещается, как и фильтры контроллеров, если вы не можете что-то сделать, это, вероятно, потому, что вы смотрите на что-то неправильно. (Помните, что Rails с гордостью называет себя «программным обеспечением»!)

Как было бы, если бы вы могли знать имя действия в методе фильтра?

Тогда у нас будет

before_filter :check_role

Что довольно СУХОЙ .

Мы могли бы определить разрешения в хэше, возможно:

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

Или что-то подобное. params [: action] работает в моей текущей версии Rails (2.1.2), хотя в книге Rails (v2) упоминается метод action_name, который мне кажется пустым.

4 голосов
/ 24 марта 2009

Вы можете использовать немного метапрограммирования. Примерно так (полностью не проверено, просто чтобы дать вам представление о том, как это может происходить):

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 голосов
/ 24 марта 2009

Я не верю, что вы можете передавать параметры в фильтры. Поэтому в прошлом я делал статические методы, которые передают параметр методу, которому нужны параметры.

Так что у меня было бы что-то вроде этого:

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 и еще не разобрался в этом;)

0 голосов
/ 01 января 2014

это старый вопрос, но если кто-то все еще задается вопросом, хороший ответ для рельсов 4 можно найти здесь

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...