5

Diciamo che ho una matrice (ricevuto dal lato client) di ID:Utilizzando DOVE IN con Rails sintassi dell'istruzione preparata

myArray = [1,5,19,27]

E Vorrei restituire tutti gli articoli per i quali il (secondario) id è in quella lista.

In SQL questo sarebbe:

SELECT * FROM Items WHERE id IN (1,5,19,27)

Sono consapevole che avrei potuto fare:

Item.where(id: [1,5,9,27]),

tuttavia la più dove query che questo sarebbe stato appiccicato sul usa la sintassi di istruzione preparata Item.where('myAttrib = ? AND myOtherAttrib <> ? AND myThirdAttrib = ?', myVal[0], myVa[1], myVal[2])

tenendo conto di ciò che ho vorrei è il seguente:

Item.where('id IN ?', myArray)

tuttavia, che produce un errore di sintassi:

ActiveRecord::StatementInvalid: PG::Error: ERROR: syntax error at or near "1" LINE 1: SELECT "items".* FROM "items" WHERE (id in 1,2,3,4)

Come posso ovviare a questo? Qual è il modo corretto per utilizzare dove con la sintassi di istruzione preparata per le espressioni IN.

risposta

2

È necessario modificare la tua ricerca per il seguente:

Item.where('id = ?', myArray) 

ActiveRecord verrà poi convertire questo a una clausola IN se myArray è, infatti, un array.

6

ho finito per usare:

Item.where('id IN (?)', myArray)

0

Il problema con l'utilizzo di SQL prime è che la si perde la namespacing automatica dei nomi delle colonne i thats fornito gratuitamente da Rails e AREL.

L'utilizzo di sql raw può iniziare a causare problemi durante la combinazione e l'unione di query o ambiti o durante l'unione.

necessità di utilizzare SQL prime da utilizzare IN:

Item.where(:id => myArray) # SELECT * FROM items WHERE id IN (...) 

myArray può essere sia una matrice di valori o una matrice di Items, o un singolo valore.

Rails è abbastanza intelligente da modificare l'SQL in base a ciò che intendi. Infatti, se la matrice contiene nil, SQL sarà SELECT * FROM items WHERE (id IS NULL or id IN (...)). Questo è chiaramente superiore all'utilizzo di SQL raw che è statico e in grado di gestire solo un caso singolo.

Se Rails non fornisce ciò che è necessario, è possibile tornare ad AREL. Ad esempio:

class Item 
    scope :with_category, ->(categories) { 
    where(arel_table[:category].in(categories)) 
    } 

    scope :filter, ->(a, b, c) { 
    not_b = arel_table[:myOtherAttrib].not_eq(b) 
    where(:myAttrib => a, :myThirdAttrib => c).where(not_b) 
    } 
end 

Item.with_category(['small', 'large']).filter(*myVal)