J'ai eu besoin récemment de faire des "ou" (or) avec ActiveRecord, pas moyen
de faire des ActiveRelation car à chaque méthode where() appelée, ActiveRecord
fait un "et" (and). Le nombre de conditions doit également être variable.
Car dans cet exemple : je veux remonter les contacts qui veulent bien être
contacté par sms OU BIEN par email OU BIEN par courrier.
Si j'avais fait ceci dans le but de remonter les contacts qui veulent être
contacté par courrier :
armailing.where(' "contacts"."by_email" = ?
OR "contacts"."by_sms" = ? OR "contacts"."by_letter" = ? ',
false, false, true)
Cela m'aurait aussi remonté les contacts ne désirant pas être contacté par
email ainsi que les contacts ne désirant pas être contacté par sms en plus des
contacts souhaitant être contacté pas courrier !
donc voici ce que je devrais faire :
armailing.where(' "contacts"."by_letter" = ? ',
true)
Et maintenant si je veux pouvoir remonter les contacts souhaitant être
contacté par sms ou courrier et que je fais :
armailing.where(' "contacts"."by_email" = ?
OR "contacts"."by_sms" = ? OR "contacts"."by_letter" = ? ',
false, true, true)
Même problème que tout à l'heure ici ActiveRecord va également remonter les
contacts ne désirant pas être contacté par email, voici comment faire :
armailing.where(' "contacts"."by_sms" = ?
OR "contacts"."by_letter" = ? ', true, true)
Donc pour finir voici la solution pour tous les cas :
array_of_conditions = []
condsms = true #ou false
if condsms then
array_of_conditions << '"contacts"."by_sms" = ?'
end
condemail = false #ou true
if condemail then
array_of_conditions << '"contacts"."by_email" = ?'
end
condletter = true #ou false
if condletter then
array_of_conditions << '"contacts"."by_value" = ?'
end
if not array_of_conditions.empty? then
armailing = armailing.where("(" + array_of_conditions.join(" OR ") + ")", *Array.new(array_of_conditions.length, true))
end
De ce fait ici je dois passer à ActiveRecord un tableau de taille variable à
la méthode where(). Et un tableau est différent d'une liste d'argument :
armailing = armailing.where(".... ? ..... ? ....? ", [true, true,
true])
Différent de :
armailing = armailing.where(".... ? ..... ? ....? ", true, true,
true)
La parade c'est d'utiliser les varargs avec le signe *.
armailing = armailing.where(".... ? ..... ? ....? ",
*[true, true, true])
Pareil que :
armailing = armailing.where(".... ? ..... ? ....? ", true, true,
true)
Bon coding !