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 !