before_filter con parámetros

84

Tengo un método que hace algo como esto:

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

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

También quiero usar este método en algunos otros controladores, así que copié el método en un ayudante que se incluye en application_controller.

el problema es que, en algunos controladores, la identificación del proyecto no es el :idsímbolo sino fe :project_id(y también :idestá presente (para otro modelo)

Como resolverías este problema? ¿Existe una opción para agregar un parámetro a la acción before_filter (para pasar el parámetro correcto)?

elegir
fuente

Respuestas:

86

Lo haría así:

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

¿Dónde correct_id_hereestá la identificación relevante para acceder a un Project.

Alex
fuente
2
¿Hay alguna forma de agregar un ,:only => [:show]símbolo? Recibo un error al intentarlobefore_filter { |c| c.authenticate_rights correct_id_here }, :only => [:show]
elija
27
Probar el otro en torno manera: before_filter(:only => [:show]) { <block_code_here> }. Más ejemplos aquí: apidock.com/rails/ActionController/Filters/ClassMethods/…
fguillen
1
Si asegura esto haciendo que el before_filtermétodo sea privado, entonces quizás vuelva a factorizar (por ejemplo, muévalo a un controlador principal, ApplicationController, etc.), deberá usarlo c.send(:filter_name, ...)ya que el filtro no se ejecutará en el contexto del controlador. guides.rubyonrails.org/…
Richard Michael
2
Hacer esto hace que el before_filter no se pueda anular / omitir debido a la falta de un nombre (proc). Los valores que quiero transmitir son a nivel de clase. ¿Es eso posible?
oreoshake
1
@oreoshake: tengo el mismo problema. ¿Encontraste una solución?
marcus3006
67

Con algo de azúcar sintáctico:

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

O si decides ponerte aún más elegante:

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

Y desde before_actionque before_filterse introdujo Rails 4 , un sinónimo de , se puede escribir como:

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

nótese bien

->significa lambda, llamado lambda literal , introducir en Ruby 1.9

%i creará una matriz de símbolos

Vadym Tyemirov
fuente
5
Esta respuesta es más elegante porque la lambda se predetermina al contexto de ejecución de la clase, por lo tanto, los métodos privados se pueden llamar sin usar '.send'
David Pelaez
@Vadym Tyemirov ¿Es find_campaignel nombre del método privado? En param=params[:id], ¿es paramel nombre de la nueva variable local que se le pasará como argumento find_campaign? Es decir, que dentro del find_campaignmétodo privado en sí, usamos paramno, params{:id]?
ahnbizcad
1
find_campaignpodría ser cualquiera, pero lo haría privado para asegurarnos de no exponer lo que no se consume. paramses una variable hash disponible para nuestros métodos, parames cualquier variable que deba pasar al método find_campaign, por ejemplobefore_action ->(campaign_id=params[:id]) { find_campaign(campaign_id) }, only: %i| show edit update destroy |
Vadym Tyemirov
14

Para continuar con la respuesta de @alex, si lo desea :excepto :onlyalgunos métodos, aquí está la sintaxis:

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

Encontrado aquí .

Augustin Riedinger
fuente
5

Encuentro que el método de bloqueo usa llaves en lugar de do...endser la opción más clara

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

before_action es solo la sintaxis preferida más reciente para before_filter

Árbol sutil
fuente
-1

Esto debería funcionar:

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

Esto debería regresar params[:project_id]si está presente en el hash de params, o regresar params[:id]si no lo está.

Matheus Moreira
fuente
el problema es que a veces ambos están presentes (anidados) y encuentra un proyecto que no es el correcto.
elegir
@choise: Eso no debería suceder: si project_idestá presente, la orcláusula garantizará que se use; solo si project_idno se proporciona a, idse seleccionará el parámetro. En otras palabras: cuando se suministran ambos parámetros, la orcláusula asegura que se utilice el valor correcto, como siempre se preferirá project_id. Naturalmente, no querrá llamar a este método cuando ninguno de los dos está presente, o cuando no hay project_idpero hay un idque no hace referencia a un proyecto.
Ola Tuvesson