ruby on rails 3 - query - Cómo especificar valores múltiples en donde con la interfaz de consulta AR en rails3
raw query ruby on rails (7)
Parece que estás haciendo algo como esto:
Model.where("attribute = ? OR attribute2 = ?", [value, value])
Mientras que necesita hacer esto:
#notice the lack of an array as the last argument Model.where("attribute = ? OR attribute2 = ?", value, value) Have a
mira http://guides.rubyonrails.org/active_record_querying.html#array-conditions para más detalles sobre cómo funciona esto.
Estaba realmente cerca. Puede convertir una matriz en una lista de argumentos con * my_list.
Model.where("id = ? OR id = ?", *["1", "2"])
O
params = ["1", "2"]
Model.where("id = ? OR id = ?", *params)
Deberia trabajar
De acuerdo con la sección 2.2 de la guía de rieles en la interfaz de consulta de Active Record here :
lo cual parece indicar que puedo pasar una cadena que especifica la (s) condición (es), luego una matriz de valores que debería ser sustituida en algún momento mientras se construye el arel. Así que tengo una declaración que genera mi cadena de condiciones, que puede ser un número variable de atributos encadenados junto con AND u OR entre ellos, y paso una matriz como el segundo arg al método where, y obtengo:
ActiveRecord :: PreparedStatementInvalid: número incorrecto de variables de vinculación (1 de 5)
lo que me lleva a creer que estoy haciendo esto incorrectamente. Sin embargo, no encuentro nada sobre cómo hacerlo correctamente. Para replantear el problema de otra manera, necesito pasar una cadena al método where como "table.attribute =? AND table.attribute1 =? O table.attribute1 =?" con un número desconocido de estas condiciones anded u ore juntas, y luego pasar algo, lo que pensé que sería una matriz como el segundo argumento que se utilizaría para sustituir los valores en la cadena de condiciones de primer argumento. ¿Es este el enfoque correcto o simplemente me falta algún otro concepto enorme en algún lado y me estoy equivocando? Pensaría que de alguna manera, esto tiene que ser posible, solo generar una cadena sql en bruto.
En lugar de pasar el mismo parámetro varias veces a where()
como este
User.where(
"first_name like ? or last_name like ? or city like ?",
"%#{search}%", "%#{search}%", "%#{search}%"
)
puede proporcionar fácilmente un hash
User.where(
"first_name like :search or last_name like :search or city like :search",
{search: "%#{search}%"}
)
eso hace que tu consulta sea mucho más legible para largas listas de argumentos.
Esto es bastante simple:
Model.where(attribute: [value1,value2])
Parece que estás haciendo algo como esto:
Model.where("attribute = ? OR attribute2 = ?", [value, value])
Mientras que necesita hacer esto:
# notice the lack of an array as the last argument
Model.where("attribute = ? OR attribute2 = ?", value, value)
Eche un vistazo a http://guides.rubyonrails.org/active_record_querying.html#array-conditions para obtener más detalles sobre cómo funciona esto.
Puede usar un hash en lugar de una cadena. Construya un hash con todas las condiciones y valores correspondientes que tenga y colóquelo en el primer argumento del método where.
Si quiere encadenar una lista abierta de condiciones (nombres de atributos y valores), sugeriría usar una tabla arel.
Es un poco difícil dar detalles ya que su pregunta es tan vaga, así que solo explicaré cómo hacer esto para un caso simple de un modelo de Post
y algunos atributos, por ejemplo, title
, summary
y user_id
usuario (es decir, un usuario tiene has_many
publicaciones )
Primero, obtenga la tabla arel para el modelo:
table = Post.arel_table
Luego, comience a construir su predicado (que eventualmente usará para crear una consulta SQL):
relation = table[:title].eq("Foo")
relation = relation.or(table[:summary].eq("A post about foo"))
relation = relation.and(table[:user_id].eq(5))
Aquí, la table[:title]
, la table[:summary]
y la table[:user_id]
son representaciones de columnas en la tabla de posts
. Cuando llama a table[:title].eq("Foo")
, está creando un predicado, más o menos equivalente a una condición de búsqueda (obtenga todas las filas cuya columna de título sea igual a "Foo"). Estos predicados se pueden encadenar junto con and
y or
.
Cuando su predicado agregado está listo, puede obtener el resultado con:
Post.where(relation)
que generará el SQL:
SELECT "posts".* FROM "posts"
WHERE (("posts"."title" = "Foo" OR "posts"."summary" = "A post about foo")
AND "posts"."user_id" = 5)
Esto te dará todas las publicaciones que tienen el título "Foo" o el resumen "Una publicación sobre foo", y que pertenecen a un usuario con id 5.
Observe la forma en que los predicados arel se pueden encadenar interminablemente para crear consultas cada vez más complejas. Esto significa que si tiene (por ejemplo) un hash de pares de atributo / valor y alguna forma de saber si usar AND
u OR
en cada uno de ellos, puede recorrerlos uno por uno y desarrollar su condición:
relation = table[:title].eq("Foo")
hash.each do |attr, value|
relation = relation.and(table[attr].eq(value))
# or relation = relation.or(table[attr].eq(value)) for an OR predicate
end
Post.where(relation)
Además de la facilidad de las condiciones de encadenamiento, otra ventaja de las tablas arel es que son independientes de la base de datos, por lo que no tiene que preocuparse de si su consulta MySQL funcionará en PostgreSQL, etc.
Aquí hay un Railscast con más información sobre arel: http://railscasts.com/episodes/215-advanced-queries-in-rails-3?view=asciicast
Espero que ayude.
INCORRECTO Esto es lo que solía hacer por alguna razón.
keys = params[:search].split('','').map!(&:downcase)
# keys are now [''brooklyn'', ''queens'']
query = ''lower(city) LIKE ?''
if keys.size > 1
# I need something like this depending on number of keys
# ''lower(city) LIKE ? OR lower(city) LIKE ? OR lower(city) LIKE ?''
query_array = []
keys.size.times { query_array << query }
#[''lower(city) LIKE ?'',''lower(city) LIKE ?'']
query = query_array.join('' OR '')
# which gives me ''lower(city) LIKE ? OR lower(city) LIKE ?''
end
# now I can query my model
# if keys size is one then keys are just ''brooklyn'',
# in this case it is ''brooklyn'', ''queens''
# @posts = Post.where(''lower(city) LIKE ? OR lower(city) LIKE ?'',''brooklyn'', ''queens'' )
@posts = Post.where(query, *keys )
ahora sin embargo, sí, es muy simple. como mencionó nfriend21
Model.where(attribute: [value1,value2])
hace lo mismo