before_filter z parametrami

84

Mam metodę, która robi coś takiego:

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

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

Chcę również użyć tej metody w niektórych innych kontrolerach, więc skopiowałem metodę do pomocnika, który jest zawarty w application_controller.

problem polega na tym, że w niektórych kontrolerach id projektu nie jest :idsymbolem, ale fe :project_id(a także :idwystępuje a (dla innego modelu)

Jak rozwiązałbyś ten problem? czy istnieje opcja dodania parametru do akcji before_filter (w celu przekazania odpowiedniego parametru)?

wybierz
źródło

Odpowiedzi:

86

Zrobiłbym to tak:

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

Gdzie correct_id_herejest odpowiedni identyfikator, aby uzyskać dostęp do pliku Project.

Alex
źródło
2
czy istnieje sposób na dodanie ,:only => [:show]symbolu? before_filter { |c| c.authenticate_rights correct_id_here }, :only => [:show]
pojawia
27
Spróbuj na odwrót: before_filter(:only => [:show]) { <block_code_here> }. Więcej przykładów tutaj: apidock.com/rails/ActionController/Filters/ClassMethods/…
fguillen
1
Jeśli zabezpieczysz to przez utworzenie before_filtermetody prywatnej, a następnie możesz ponownie uwzględnić (np. Przenieść ją do kontrolera nadrzędnego, ApplicationController itp.), Będziesz musiał użyć, c.send(:filter_name, ...)ponieważ filtr nie będzie działał w kontekście kontrolera. guide.rubyonrails.org/…
Richard Michael
2
Dzięki temu filtr before_filter nie może zostać przesłonięty / pominięty z powodu braku nazwy (proc). Wartości, które chcę przekazać, to poziom klasy. Czy to jest możliwe?
oreoshake
1
@oreoshake: mam ten sam problem. Znalazłeś rozwiązanie?
marcus3006
67

Z odrobiną cukru syntaktycznego:

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

Lub jeśli zdecydujesz się na jeszcze bardziej wymyślny:

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

A ponieważ Rails 4 before_action, synonim nazwy before_filter, został wprowadzony, można to zapisać jako:

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

NB

->oznacza lambda, zwany literałem lambda , wprowadzony w Rubim 1.9

%i utworzy tablicę symboli

Vadym Tyemirov
źródło
5
Ta odpowiedź jest bardziej elegancka, ponieważ lambda domyślnie przyjmuje kontekst wykonania klasy, stąd metody prywatne mogą być wywoływane bez użycia '.send'
David Pelaez
@Vadym Tyemirov Czy find_campaignnazwa metody prywatnej? W param=params[:id], paramczy nazwa nowej zmiennej lokalnej, która zostanie przekazana jako argument do find_campaign? Co oznacza, że w find_campaignsamej metodzie prywatnej, używamy paramnie params{:id]?
ahnbizcad
1
find_campaignmoże być albo, ale uczyniłbym to prywatnym, aby mieć pewność, że nie ujawnimy tego, co nie jest skonsumowane. paramsjest zmienną hash dostępną dla naszych metod, paramjest dowolną zmienną, którą trzeba przekazać do metody find_campaign, np.before_action ->(campaign_id=params[:id]) { find_campaign(campaign_id) }, only: %i| show edit update destroy |
Vadym Tyemirov
14

Aby kontynuować odpowiedź @alex, jeśli chcesz :exceptlub :onlyniektóre metody, oto składnia:

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

Znaleziono tutaj .

Augustin Riedinger
źródło
5

Uważam, że metoda blokowa używa nawiasów klamrowych zamiast do...endbyć najwyraźniejszą opcją

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

before_action jest po prostu nowszą preferowaną składnią dla before_filter

Subtletree
źródło
-1

To powinno działać:

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

Powinien powrócić, params[:project_id]jeśli jest obecny w hashu params, lub zwrócić, params[:id]jeśli nie jest.

Matheus Moreira
źródło
problem polega na tym, że czasami oba są obecne (zagnieżdżone) i znajduje projekt, który nie jest właściwy.
wybierz
@choise: To nie powinno się zdarzyć: jeśli project_idjest obecna, orklauzula zapewni, że zostanie to użyte - tylko jeśli project_idnie zostanie idpodany parametr, zostanie wybrany. Innymi słowy: gdy podane są oba parametry, orklauzula zapewnia użycie poprawnej wartości, co zawsze będzie preferowane project_id. Oczywiście nie chcesz wywoływać tej metody, gdy żadna z nich nie jest obecna lub gdy nie ma, project_idale istnieje, idktóra nie odwołuje się do projektu.
Ola Tuvesson