2010-07-20 13 views
50

necesito una instrucción SQL que comprobar si una condición es satisfecha:Ruby on Rails 3 howto marca 'O' condición

SELECT * FROM my_table WHERE my_table.x=1 OR my_table.y=1 

quiero hacer esto el 'Rails 3' manera. Estaba buscando algo como:

Account.where(:id => 1).or.where(:id => 2) 

Sé que siempre puedo recurrir a sql o una cadena de condiciones. Sin embargo, en mi experiencia, esto a menudo conduce al caos cuando se combinan ámbitos. ¿Cuál es la mejor manera de hacer esto?

Otra pregunta relacionada es cómo describir la relación que depende de una condición OR. La única forma en que encontré:

has_many :my_thing, :class_name => "MyTable", :finder_sql => 'SELECT my_tables.* ' + 'FROM my_tables ' + 
'WHERE my_tables.payer_id = #{id} OR my_tables.payee_id = #{id}' 

Sin embargo, estas vueltas se rompen cuando se usan en combinaciones. ¿Hay una mejor manera de especificar esto?

Respuesta

9

Lamentablemente, el .o aún no está implementado (pero cuando lo es, que va a ser impresionante).

Por lo que usted tiene que hacer algo como:

class Project < ActiveRecord::Base 
    scope :sufficient_data, :conditions=>['ratio_story_completion != 0 OR ratio_differential != 0'] 
    scope :profitable, :conditions=>['profit > 0'] 

De esa manera usted todavía puede ser impresionante y hacer:

Project.sufficient_data.profitable 
+0

del sitio arel github: El operador OR aún no es compatible. Funcionará así: users.where (users [: name] .eq ('bob'). Or (users [: age] .lt (25))) – hjuskewycz

6

me gustaría ir con la cláusula de IN, por ejemplo:

Account.where(["id in (?)", [1, 2]]) 
+0

que serían apropiadas, de notar el autor es buscando en 2 campos diferentes ... – Brian

+0

Oh sí, es cierto, escribí la respuesta basada en esta declaración 'Account.where (: id => 1) .or.where (: id => 2)'. Obviamente no funciona para diferentes campos. – jpemberthy

+2

No funcionará si uno de los valores en el conjunto es 'nil'. Digamos que quiere encontrar todos los registros donde "visto" sea 'false' o' nil' y usted haga 'Notification.where (: viewed => [false, nil])', no funcionará, ya que MySQL requiere el la sintaxis 'viewed = 0 OR seen IS NULL' y * no funcionarán con *' viewed = 0 OR viewed = NULL' o 'seen IN (0, NULL)'. –

71

Esta voluntad trabaja en los carriles 5, ver rails master:

Post.where('id = 1').or(Post.where('id = 2')) 
# => SELECT * FROM posts WHERE (id = 1) OR (id = 2) 

Para Rails 3.0.4+:

accounts = Account.arel_table 
Account.where(accounts[:id].eq(1).or(accounts[:id].eq(2))) 
+12

Esta sintaxis funciona. ¿Alguien más no le gusta? :) –

+4

Definitivamente no me gusta esta sintaxis. Aún así, sin embargo, interesante. – DRobinson

+0

Me gusta porque puede ser combinatorio – mdesantis

16

Estas consultas son ilegibles para mí.

¿Qué pasa con una cadena SQL? De hecho, los rieles Guías expone de esta manera como la primera forma de hacer que las condiciones en las consultas: http://guides.rubyonrails.org/active_record_querying.html#array-conditions

Así, apuesto a que para esta forma de hacerlo como el "camino carriles":

Account.where("id = 1 OR id = 2") 

En mi humilde opinión, es más corto y más claro.

+7

Prefiero esto, pero usaría valores parametrizados. 'Account.where (" id =? OR id =? ", 1,2)' – spyle

+0

No veo ninguna razón para valores parametrizados cuando uso números simples. –

+0

Si está codificando el ID, entonces no hay números simples, pero sospecho que se devuelven desde otro lado, por lo que el camino a seguir paramterizar es evitar la inyección de sql. –

5

He utilizado la gema Squeel (https://github.com/ernie/squeel/) para hacer consultas OR y funciona muy bien.

Se le permite escribir sus consultas como Account.where{(id == 1) | (id == 2)}

4

Se puede definir una matriz como valor en el :conditions Hash.

Por lo que podría hacer por ejemplo:

Account.all(:conditions => { :id => [1, 2] }) 

Probado con rieles 3.1.0

+1

esto es ineficiente porque está recuperando todos los artículos de la base de datos y revisando en la memoria –

111

Account.where(id: [1,2]) ninguna explicación necesaria.

+0

El más limpio, DRYest que he visto. ¡Buen trabajo! –

+0

¡la mejor solución que he visto! Y parecía suficiente (: –

+10

Esto es genial, y tan simple. También aprendí que puedes usar 'nil' de forma segura: por ejemplo' Thing.where (foo: [1, nil]) 'se traducirá a' SELECT ' cosas ". * DE" cosas "DONDE ((" cosas "." foo "= 1 O" cosas "." foo "ES NULO))' ¡Brillante! –

2

alternativo sintaxis usando Hash

Account.where("id = :val1 OR id = :val2", val1: 1, val2: 2). 

Esto es particularmente útil, cuando el valor se compara con múltiples columnas. por ejemplo:

User.where("first_name = :name OR last_name = :name", name: 'tom') 
0

Con rails_or, que podría hacerlo como:

Account.where(id: 1).or(id: 2) 

(. Funciona en los carriles 4 y 5, también)