Condiciones con variables de enlace y parámetros opcionales
-
10-07-2019 - |
Pregunta
Digamos que tengo un formulario donde los usuarios pueden buscar personas cuyo nombre comience con una cadena particular de name
, por ejemplo, " Mi " encontraría '' Mike '' y "Miguel". Probablemente crearía una declaración de búsqueda como esta:
find(:all, :conditions => ['name LIKE ?', "#{name}%"])
Digamos que el formulario también tiene dos campos opcionales, hair_color
y eye_color
que se pueden usar para filtrar aún más los resultados. Ignorando la parte del nombre de la consulta, una declaración de búsqueda para personas que pueden tomar un número arbitrario de parámetros opcionales podría verse así:
find (: all,: condition = > {params [: person]})
Que para mis dos parámetros opcionales se comportaría como el equivalente de esto:
find (: all,: condition = > {: hair_color = > hair_color,: eye_color = > eye_color})
Lo que no puedo entender es cómo fusionar estos dos tipos de consultas donde el campo requerido, "nombre" se aplica a los "como" condición anterior, y los parámetros opcionales hair_color
y eye_color
(y quizás otros) se pueden agregar para filtrar aún más los resultados.
Ciertamente puedo construir una cadena de consulta para hacer esto, pero creo que debe haber una "vía de rieles". Eso es más elegante. ¿Cómo puedo fusionar parámetros obligatorios de enlace con parámetros opcionales?
Solución
Este es el uso perfecto de un ámbito con nombre.
cree un ámbito con nombre en el modelo:
named_scope :with_name_like, lambda {|name|
{:conditions => ['name LIKE ?', "#{name}%"]}
}
En este punto puedes llamar
Model.with_name_like("Mi").find(:all, :conditions => params[:person])
Y Rails fusionará las consultas por usted.
Editar: Código para Waseem:
Si el nombre es opcional, puede omitir el ámbito con nombre de su cadena de método con una condición if:
unless name.blank?
Model.with_name_like("Mi").find(:all, :conditions => params[:person])
else
Model.find(:all, :conditions => params[:person])
end
O podría redefinir el alcance nombrado para hacer lo mismo.
named_scope :with_name_like, lambda {|name|
if name.blank?
{}
else
{:conditions => ['name LIKE ?', "#{name}%"]}
end
}
Update
Aquí está la versión Rails 3 del último fragmento de código:
scope :with_name_like, lambda {|name|
if not name.blank?
where('name LIKE ?', "#{name}%")
end
}
Otros consejos
¿Para cumplir también con la solicitud de Waseem, pero dejando nulo en lugar de estar en blanco? (lo cual es falso en caso de que quiera usar " @things = Thing.named_like (params [: name]) " directamente)
named_scope :named_like, lambda do |*args|
if (name=args.first)
{:conditions => ["name like ?",name]}
else
{}
end
end
# or oneliner version:
named_scope :named_like, lambda{|*args| (name=args.first ? {:conditions => ["name like ?",name]} : {}) } }
Espero que ayude