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 !