Reputation: 55
I need the includes Table to retrieve the records that are NOT nil. I need to keep the included: true in the query.
Using postgres.
Role has many tasks.
Tasks belongs to a Role.
Task.includes(:role).where(included: true, roles: {doer: nil})
The next part is the IDEA of what I want... but obviously syntax is wrong in the where clause's "roles" value.
Task.includes(:role).where(
included: true,
roles: {
doer != nil #=> where 'doer' is not 'nil'
})
I'm looking for an efficient query which is why i did the includes. I don't know how to get this without multiple where queries.
If you understand the question but think it could be asked better to be more clear, let me know. I couldn't any clues for this answer anywhere unless multiple where statments are used.
Upvotes: 1
Views: 3690
Reputation: 1163
I prefer to avoid strings when possible, so I'd use the following:
Task.includes(:role).where(included: true).where.not(roles: { doer: nil })
If you have specifically set the included
column on the tasks
table to have NULL FALSE
, you could also condense the where
calls into a single call, although this will still only launch one query:
Task.includes(:role).where.not(included: false, roles: { doer: nil })
Personally, I'd like to see this cleaned-up a bit with some scopes, providing that these calls are commonplace. Something like:
scope :with_doer, -> { includes(:role).where.not(roles: { doer: nil }) }
so the resulting code would be more readable:
Task.with_doer.where(included: true)
You could obviously extend this pattern to the included: true
bit as well.
Note that ActiveRecord queries are built up and then kicked to the database with a "kicker" which Rails kind of sneakily and hackily does through #inspect
or #to_a
most of the time. So, you don't need to worry about needing to condense the where
calls into a single call.
Upvotes: 2
Reputation: 7339
What about something like:
Task.includes(:roles).where.not('roles.doer' => nil)
This is a rails 4-and-up convention, for rails 3 it would be something like:
Task.includes(:roles).where("roles.doer IS NOT NULL")
And you don't need the included attribute, it can be removed from the model for these purposes.
Since you do seem to need included
(oops)
Task.includes(:roles).where('tasks.included' => true, 'roles.doer' => !nil)
Aaah.. how i love postgres.. When you're asking for efficiency, I think this fails, but I'm returning correct results. If you benchmark the options, this is correct (I think) but slow.
Task.joins('LEFT OUTER JOIN "roles" ON roles.user_id = user_id').where("tasks.included IS true AND roles.doer IS NOT NULL")
Upvotes: 2
Reputation: 119
Write SQL statements like this?
Task.includes(:role).where("included = 'true' AND roles.doer NOT 'nil'")
Upvotes: 0