2012-03-14 26 views
35

Tengo un modelo llamado Tema, que tiene un nombre como campo.Rieles: cómo buscar_por un campo que contiene una cierta cadena

Digamos que tengo un término que estoy buscando, apple.

Si hago un

Topic.find_by_name("apple") 

puedo obtener un registro de vuelta con el nombre de manzana. Eso está bien, pero ¿cómo cambio find_by_name para que pueda encontrar "apple juice" además de "apple", básicamente, encontrar nombres que contengan la consulta original o que coincidan exactamente con la consulta original?

Edit: Gracias por la respuesta. Supongo que debería haber sido un poco más claro antes, pero ¿y si quiero encontrarlo por un nombre de variable (obviamente no voy a querer encontrar el nombre "manzana" cada vez :))?

¿Cómo manipulo Topic.where para acomodar esto? Así algo así como ...

@topic = Topic.where(......., @name) 
+0

añadido una edición a mi respuesta relacionada con su última edición, que me haga saber si eso ayuda! – Deleteman

+0

Ver mi comentario a la respuesta de @ Alisher para responder a su pregunta editada. 'Topic.where (" name like? "," # {@ Name}% ")' sería de una sola manera. –

Respuesta

82

creo que algo como esto debería funcionar:

Topic.where("name like ?", "%apple%") 

para acomodar por tu edición:

Topic.where("name like ?", "%#{@search}%") 

interpolación de cadenas básico, que está utilizando el valor de @search dentro de la cadena %%, entonces usted @search = "apple" luego termina con %apple%

+1

¿Cree que este método conduce a la inyección SQL? –

+2

Por lo que puedo decir [aquí] (http://rails-sqli.org/) el método 'where' no hace nada para proteger contra la inyección de SQL. Sin embargo, la pregunta solo puede ser respondida al considerar si esa variable está alguna vez expuesta a la entrada del usuario, ya sea a través de un valor no optimizado almacenado, o directamente. Esa debería ser la pregunta de interés. La mejor forma de contrarrestar la inyección SQL es desinfectar los valores al ingresar la aplicación, incluso antes del almacenamiento. – GKnight

+0

¿qué tal no contiene una cierta cadena? – zx1986

0

Trate

Topic.where("name like ?",'%apple%') 
Topic.find(:all, :conditions => ["name like ?","%apple%"]) 
+0

La inyección SQL en el primer ejemplo, debe ser 'Topic.where ('name like?',"% Apple% ")'. El segundo está bien. –

+0

ya estás en lo correcto. – asitmoharna

+0

También puede hacer esto en Rails 4+: 'Topic.find_by (" name like? ","% Apple% ")' –

9

Parece que en Rails 3 que se quiere utilizar el donde:

Topic.where("name ILIKE ?", "%apple%") 
+1

No estoy seguro si esto funcionaría - ¿es "~ =" sql válido? ¿O estás pensando en el patrón de ruby ​​matcher "= ~". Si es así, no funcionaría aquí, ya que no es sql –

+0

Sí, me di cuenta de que en la publicación que mencioné y la tomé por su valor nominal ... Cambiaré a LIKE y estaré seguro. ¡Gracias! – ScottJShea

+5

El operador '~ =' funciona para PostgreSQL, es una coincidencia de expresiones regulares. Pero sí, la respuesta de Scott debería funcionar. Es posible que desee utilizar ILIKE, que ofrece una búsqueda que no distingue entre mayúsculas y minúsculas. –

7

No ponga cadena directamente por el estilo. Se llama inyección SQL. En su lugar debe usar .where:

Topic.where("name like '?%' ", params[:name]) 
+0

¿Se supone que es "name like '?%'" O "name like '%?%'" – varatis

+3

Esto no funcionará exactamente como se indicó porque Rails citará automáticamente la cadena . Tendrá que virar el '%' antes de la sustitución, por ejemplo 'Topic.where ('name like?'," # {Params [: name]}% ").' –

+0

Beautiful answer. –

2

Con PostgreSQL también se puede utilizar match operators:

Topic.where("name ~* ?", @search) 
Cuestiones relacionadas