Reputation: 632
I have a has_many :through relationship set up like so
class Situation < ActiveRecord::Base
has_many :notifications
has_many :notiftypes, through: :notifications
end
class Notification < ActiveRecord::Base
belongs_to :situation
belongs_to :notiftype
end
class Notiftype < ActiveRecord::Base
has_many :notifications
has_many :situations, through: :notifications
end
So, a Situation has many Notifications, which can be of many types (Notiftype).
My problem is trying to query for the notiftypes
that have not been set for a particular situation
.
Want to find records with no associated records in Rails 3
The answers in that question get me close, but only to the point of finding Notiftypes that have not been set AT ALL.
If this were the standard :situation
has_many :notiftypes
I could just do a Left Outer Join like so
myquery = Notiftype.joins('LEFT OUTER JOIN situations ON situations.notiftype_id = notiftype.id').where('notiftype_id IS NULL')
but I'm really not sure how to do this with the intermediate table between them.
I have been trying consecutive joins but it's not working. I'm not sure how to join the two separated tables.
Can anyone explain the right way to query the db? I am using SQLite, Rails 3.1, Ruby 1.9.2 right now, but likely Postgresql in the future.
Upvotes: 1
Views: 727
Reputation: 64363
Try this:
class Situation < ActiveRecord::Base
# ...
has_many :notiftypes, through: :notifications do
def missing(reload=false)
@missing_notiftypes = nil if reload
@missing_notiftypes ||= proxy_owner.notiftype_ids.empty? ?
Notiftype.all :
Notiftype.where("id NOT IN (?)", proxy_owner.notiftype_ids)
end
end
end
Now to get the missing Notiftype
situation.notiftypes.missing
If you want to further optimize this to use one SQL rather than two you can do the following:
class Situation < ActiveRecord::Base
# ...
has_many :notiftypes, through: :notifications do
def missing(reload=false)
@missing_notiftypes = nil if reload
@missing_notiftypes ||= Notiftype.joins("
LEFT OUTER JOIN (#{proxy_owner.notiftypes.to_sql}) A
ON A.id = notiftypes.id").
where("A.id IS NULL")
end
end
end
You can access the missing Notifytypes as:
situation.notiftypes.missing
Upvotes: 0