before_filter с параметрами

84

У меня есть метод, который делает что-то вроде этого:

before_filter :authenticate_rights, :only => [:show]

def authenticate_rights
  project = Project.find(params[:id])
  redirect_to signin_path unless project.hidden
end

Я также хочу использовать этот метод в некоторых других контроллерах, поэтому я скопировал метод в помощник, который включен в application_controller.

проблема в том, что в некоторых контроллерах идентификатор проекта не является :idсимволом, а является fe :project_id(а также :idприсутствует (для другой модели)

Как бы вы решили эту проблему? есть ли возможность добавить параметр к действию before_filter (чтобы передать правильный параметр)?

выбрать
источник

Ответы:

86

Я бы сделал так:

before_filter { |c| c.authenticate_rights correct_id_here }

def authenticate_rights(project_id)
  project = Project.find(project_id)
  redirect_to signin_path unless project.hidden
end

Где correct_id_hereсоответствующий идентификатор для доступа к файлу Project.

Alex
источник
2
есть ли способ добавить ,:only => [:show]символ? Я получаю ошибку , пытаясьbefore_filter { |c| c.authenticate_rights correct_id_here }, :only => [:show]
Choise
27
Попробуйте наоборот: before_filter(:only => [:show]) { <block_code_here> }. Больше примеров здесь: apidock.com/rails/ActionController/Filters/ClassMethods/…
fguillen 03
1
Если вы обезопасите это, сделав before_filterчастный метод, то, возможно, повторно фактор (например, переместите его в родительский контроллер, ApplicationController и т. Д.), Вам нужно будет использовать, c.send(:filter_name, ...)поскольку фильтр не будет работать в контексте контроллера. guides.rubyonrails.org/…
Ричард Майкл
2
Это делает так, что before_filter нельзя переопределить / пропустить из-за отсутствия имени (proc). Я хочу передать значения уровня класса. Это возможно?
oreoshake
1
@oreoshake: у меня такая же проблема. Вы нашли решение?
marcus3006
67

С некоторым синтаксическим сахаром:

before_filter -> { find_campaign params[:id] }, only: [:show, :edit, :update, :destroy]

Или, если вы решите придумать еще больше:

before_filter ->(param=params[:id]) { find_campaign param }, only: %i|show edit update destroy|

А так как был представлен before_actionсиноним Rails 4 , before_filterего можно записать как:

before_action ->(param=params[:id]) { find_campaign param }, only: %i|show edit update destroy|

NB

->означает lambda, называемый лямбда-литералом , введенный в Ruby 1.9

%i создаст массив символов

Вадим Тёмиров
источник
5
Этот ответ более элегантен, потому что лямбда по умолчанию соответствует контексту выполнения класса, поэтому частные методы могут быть вызваны без использования '.send'
Дэвид
@Vadym Tyemirov Имя find_campaignприватного метода? В param=params[:id], это paramимя новой локальной переменной, которая будет передана в качестве аргумента find_campaign? Это означает, что внутри самого find_campaignчастного метода мы используем paramnot params{:id],?
ahnbizcad
1
find_campaignможет быть любым, но я бы сделал его закрытым, чтобы убедиться, что мы не раскрываем то, что не потребляется. params- это хеш-переменная, доступная для наших методов, paramэто любая переменная, которую вам нужно передать методу find_campaign, напримерbefore_action ->(campaign_id=params[:id]) { find_campaign(campaign_id) }, only: %i| show edit update destroy |
Вадим Тимиров
14

Чтобы продолжить ответ @alex, если вы хотите :exceptили :onlyнекоторые методы, вот синтаксис:

before_filter :only => [:edit, :update, :destroy] do |c| c.authenticate_rights params[:id] end 

Нашел здесь .

Огюстен Ридингер
источник
5

Я считаю, что блочный метод использует фигурные скобки вместо того, do...endчтобы быть самым ясным вариантом

before_action(only: [:show]) { authenticate_rights(id) }

before_action это просто новый предпочтительный синтаксис для before_filter

Тонкое дерево
источник
-1

Это должно работать:

project = Project.find(params[:project_id] || params[:id])

Он должен возвращаться, params[:project_id]если он присутствует в хэше params, или возвращаться, params[:id]если его нет.

Матеус Морейра
источник
проблема в том, что иногда оба присутствуют (вложены), и он находит проект, который не подходит.
выбор
@choise: Этого не должно происходить: если project_idприсутствует, то orпредложение гарантирует, что это используется - параметр будет выбран только в том случае, если project_idне указан id. Другими словами: когда указаны оба параметра, orпредложение гарантирует, что используется правильное значение, что всегда будет предпочтительнее project_id. Естественно, вы не захотите вызывать этот метод, когда ни один из них не присутствует, или когда нет, project_idно есть, idкоторый не ссылается на проект.
Ола Тувессон