2010-09-03 16 views
148

¿Cómo se hace una consulta OR en Rails 3 ActiveRecord. Todos los ejemplos que encuentro solo tienen consultas AND.ActiveRecord O consulta

Editar: O método está disponible desde los carriles 5. Ver ActiveRecord::QueryMethods

+7

Aprende SQL. ActiveRecord hace que sea más fácil hacer que las cosas funcionen, pero aún necesita saber qué están haciendo sus consultas, de lo contrario, es posible que su proyecto no se escale. También pensé que podría salir adelante sin tener que lidiar con SQL, y estaba muy equivocado al respecto. – ryan0

+1

@ ryan0, tienes razón. Podemos usar gemas extravagantes y otras cosas, pero debemos ser conscientes de lo que estas gemas están haciendo dentro y cuál es la tecnología subyacente, y quizás usar las tecnologías subyacentes sin la ayuda de la gema, si es necesario, por el bien de actuación. Las gemas se crean con un número específico de usos en mente, pero puede haber situaciones en las que uno de los casos de uso en nuestro proyecto podría ser diferente. – rubyprince

+1

Puede ser de ayuda: [ActiveRecord O consulte la notación hash] (http://stackoverflow.com/q/31096009/3444240) – potashin

Respuesta

96

Uso ARel

t = Post.arel_table 

results = Post.where(
    t[:author].eq("Someone"). 
    or(t[:title].matches("%something%")) 
) 

El resultado ting SQL:

ree-1.8.7-2010.02 > puts Post.where(t[:author].eq("Someone").or(t[:title].matches("%something%"))).to_sql 
SELECT  "posts".* FROM  "posts" WHERE  (("posts"."author" = 'Someone' OR "posts"."title" LIKE '%something%')) 
+0

Se siente un poco desordenado, pero al menos no estoy escribiendo sql, ¡lo cual no es correcto! Tendré que estudiar el uso de Arel más. – pho3nixf1re

+0

Lo bueno es que no tiene que hacerlo todo de una vez, puede generar consultas y no llegará a la base de datos hasta que realmente necesite los datos. Este ejemplo se combinó solo por brevedad. –

+44

No puedo dejar de ver cuánto más elegante es Sequel – Macario

6

simplemente añada una o en las condiciones

Model.find(:all, :conditions => ["column = ? OR other_column = ?",value, other_value]) 
+3

Esta es más la sintaxis de Rails 2, y me obliga a escribir al menos parte de una cadena sql. – pho3nixf1re

6

El plugin MetaWhere es completamente sorprendente.

¡Mezcle fácilmente los OR's y AND's, únase a las condiciones de cualquier asociación e incluso especifique OUTER JOIN's!

136

en Rails 3, debe ser

Model.where("column = ? or other_column = ?", value, other_value) 

Esto también incluye SQL en bruto, pero no creo que hay una manera de hacer ActiveRecord operación OR. Tu pregunta no es una pregunta novato.

+34

Incluso si hay sql en bruto, esta afirmación parece mucho más clara para mí que Arel. Quizás incluso DRYer. – jibiel

+6

si necesita encadenar, otras combinaciones de tablas que pueden tener las columnas con los mismos nombres de columna, debe usarlo así, 'Page.where (" pages.column =? Or pages.other_column =? ", Value, other_value) ' – rubyprince

+1

Y eso falla si la consulta alias las tablas. Es entonces cuando arel brilla. – DGM

3

Acabo de extraer this plugin del trabajo del cliente que le permite combinar ámbitos con .or., ej. Post.published.or.authored_by(current_user). Squeel (implementación más reciente de MetaSearch) también es excelente, pero no te permite O alcances, por lo que la lógica de consulta puede ser un poco redundante.

184

Si desea utilizar un operador o sobre el valor de una columna, puede pasar una matriz a .where y ActiveRecord utilizará IN(value,other_value):

Model.where(:column => ["value", "other_value"]

salidas:

SELECT `table_name`.* FROM `table_name` WHERE `table_name`.`column` IN ('value', 'other_value') 

Esto debería lograr el equivalente de OR en una sola columna

+11

esta es la respuesta más limpia de "carriles", debería haber sido aceptada – koonse

+9

Gracias @koonse, no es * exactamente * una consulta 'O', pero produce el mismo resultado para esta situación. – deadkarma

+0

Ayuda si puede - http://stackoverflow.com/questions/15517286/transformation-of-query-to-active-record –

13

Si desea utilizar matrices como argumentos, el siguiente código funciona en los carriles 4:

query = Order.where(uuid: uuids, id: ids) 
Order.where(query.where_values.map(&:to_sql).join(" OR ")) 
#=> Order Load (0.7ms) SELECT "orders".* FROM "orders" WHERE ("orders"."uuid" IN ('5459eed8350e1b472bfee48375034103', '21313213jkads', '43ujrefdk2384us') OR "orders"."id" IN (2, 3, 4)) 

Más información: OR queries with arrays as arguments in Rails 4.

+9

O esto: 'Order.where (query.where_values.inject (: o))' para usar arel hasta el final. –

+0

> O consultas con matrices como argumentos en Rails 4. ¡Enlace útil! ¡Gracias! –

+0

Esto es asombroso. – rubyprince

38

Una versión actualizada de Rails/ActiveRecord puede admitir esta sintaxis de forma nativa.Se vería similar a:

Foo.where(foo: 'bar').or.where(bar: 'bar') 

Como se ha señalado en esta solicitud de extracción https://github.com/rails/rails/pull/9052

Por ahora, sólo tiene que pegarse con el siguiente funciona muy bien:

Foo.where('foo= ? OR bar= ?', 'bar', 'bar') 

Actualización: Según https://github.com/rails/rails/pull/16052 la or característica estará disponible en Rails 5

Actualización: característica se ha fusionado a Rails 5 rama

+0

'o' está disponible ahora Rails 5 pero no implementado de esta manera porque espera que se pase 1 argumento. Espera un objeto Arel. Ver la respuesta aceptada –

1

Con rieles + Arel, de una manera más clara:

# Table name: messages 
# 
# sender_id: integer 
# recipient_id: integer 
# content:  text 

class Message < ActiveRecord::Base 
    scope :by_participant, ->(user_id) do 
    left = arel_table[:sender_id].eq(user_id) 
    right = arel_table[:recipient_id].eq(user_id) 

    where(Arel::Nodes::Or.new(left, right)) 
    end 
end 

Produce:

$ Message.by_participant(User.first.id).to_sql 
=> SELECT `messages`.* 
    FROM `messages` 
    WHERE `messages`.`sender_id` = 1 
     OR `messages`.`recipient_id` = 1 
-2
Book.where.any_of(Book.where(:author => 'Poe'), Book.where(:author => 'Hemingway') 
+0

Agregue algunas explicaciones a su respuesta – kvorobiev

+0

Creo que Matthew se estaba refiriendo a la gema [activerecord_any_of] (https://github.com/oelmekki/activerecord_any_of) que agrega compatibilidad con esta sintaxis. – DannyB

+0

Si es cierto, gracias @DannyB. La respuesta debe explicar su contexto. – Sebastialonso

11

rieles 5 viene con un método or. (l ink to documentation)

Este método acepta un objeto ActiveRecord::Relation. por ejemplo:

User.where(first_name: 'James').or(User.where(last_name: 'Scott')) 
3

Se podía hacerlo como:

Person.where("name = ? OR age = ?", 'Pearl', 24) 

o más elegante, instalar rails_or joya y hacerlo como:

Person.where(:name => 'Pearl').or(:age => 24) 
Cuestiones relacionadas