First, using includes
when you want to do conditions on associations can have negative side effects:
- You will eager load data, which, if not needed, means doing more work for nothing
- The
addresses
that are eager loaded are only those matching the condition. So if you thn use addresses
, you don't get all of them for that record (only those that matched the condition). This causes weird bug or hard to understand working code.
To avoid this and all other issues, I recommend to use a gem I made specifically for this: activerecord_where_assoc
Your problem can be simplified, I will do so after replying to your request as-is:
You seem to be using Rails 4.2 according to the tags. So you don't yet have access to the #or method yet. So this is how you could do it:
sql_no_address = Facility.assoc_not_exists_sql(:addresses)
sql_no_city = Facility.assoc_exists_sql(:addresses) { where_assoc_not_exists(:city) }
Facility.where("#{sql_no_address} OR #{sql_no_city}")
If you have Rails 5 or more:
Facility.where_assoc_not_exists(:addresses).or(Facility.where_assoc_not_exists([:addresses, :city]))
Now, a simpler solution. Notice that if a facility has no addresses, then it cannot have a city, because it must go through an address to get to a city. Really, your problem is just "I want Facilities that have no cities". This is what passing an array to the methods do, it tries to go from one to the other until the end.
Facility.where_assoc_not_exists([:addresses, :city])
Here are the introduction and examples. Read more details in the documentation.