6

Estoy implementando una función de búsqueda simple que debe verificar una cadena en el nombre de usuario, apellido y primer nombre. Yo he visto este método ActiveRecord en un viejo Railscast:Rails ActiveRecord - Buscar en varios atributos

http://railscasts.com/episodes/37-simple-search-form

find(:all, :conditions => ['name LIKE ?', "%#{search}%"]) 

pero ¿cómo hacerlo de modo que se busca para la palabra clave en el nombre, apellidos y nombre y devuelve el registro si la uno de los campos coincide con el término?

¿Me pregunto si el código en RailsCast es propenso a las inyecciones de SQL?

¡Muchas gracias!

Respuesta

20

asumí el nombre del modelo es el modelo - simplemente reemplazarlo con el nombre del modelo real cuando lo hace la consulta real:

Model.where("name LIKE ? OR last_name LIKE ? OR first_name LIKE ?", "%#{search}%","%#{search}%","%#{search}%") 

de sus preocupaciones acerca de las inyecciones SQL - ambos de los fragmentos de código son inmunes a las inyecciones SQL . Siempre y cuando no incruste cadenas directamente en su cláusula WHERE, estará bien. Un ejemplo de código de inyección propensos sería:

Model.where("name LIKE '#{params[:name]}'") 
+0

Justo lo que necesitaba. Gracias por explicarlo claramente! – maru

+0

¿Qué sucede si el controlador se cambia para pasar el 'params' completo en lugar de' params [: search] 'y en nuestra consulta usamos' "% # {params [: search]}%" 'en vez de' "% # {búsqueda}% "'. ¿Eso todavía es inmune a las inyecciones de SQL? – Dennis

+0

@Dennis sí lo es. ¿Siempre y cuando estés usando? y pasando argumentos adicionales para reemplazarlos en la consulta, está bien. –

8

Aunque la respuesta seleccionada trabajará, he notado que se rompe si se intenta escribir una búsqueda "Raúl Riera", ya que se producirá un error en ambos casos, debido a Raul Riera tampoco es mi primer nombre o mi apellido .. es mi nombre y apellido ... lo resuelto haciendo

Model.where("lower(first_name || ' ' || last_name) LIKE ?", "%#{search.downcase}%") 
+0

Encontré esta respuesta más útil. ¡Gracias! –

+0

¿No sería mejor usar 'ILIKE' en lugar de downcase? Deje que el DB lo maneje. –

+0

No funciona cuando last_name o first_name equivale a nil, si es así, debe establecer el valor predeterminado de cadena vacía en el nombre y apellido –

0

La mejor manera de hacer esto es:

Model.where("attr_a ILIKE :query OR attr_b ILIKE :query", query: "%#{query}%") 
0

con Arel, puedes evitar escribir SQL manualmente con algo como esto:

Model.where(
    %i(name first_name last_name) 
    .map { |field| Model.arel_table[field].matches("%#{query}%") 
    .inject(:or) 
) 

Esto sería particularmente útil si la lista de campos para hacer coincidir era dinámica.

Cuestiones relacionadas