I have this relationship : a user can have zero or one dog, but a dog has to belong to someone.
# dog.rb
class Dog < ActiveRecord::Base
belongs_to :user
end
# user.rb
class User < ActiveRecord::Base
has_one :dog
end
I want to define the following scopes :
User.with_a_dog
User.without_a_dog
I can do this for the first case, because the joins are INNER JOIN by default in rails :
scope :with_a_dog, :joins(:dog)
1/开发者_Python百科 Is this solution for the first scope good enough?
2/ What would you do for the second one?
3/ (Somewhat related) Is there a better way of doing this? :
# user.rb
def has_a_dog?
!self.dog.nil?
end
Thanks for your help!
Just wanted to add this in case someone finds it useful:
user.rb
class User < ActiveRecord::Base
has_one :dog
# To get records with a dog we just need to do a join.
# AR will do an inner join, so only return records with dogs
scope :with_a_dog, -> { joins(:dog) }
# To get records without a dog, we can do a left outer join, and then only
# select records without a dog (the dog id will be blank).
# The merge with the Dog query ensures that the id column is correctly
# scoped to the dogs table
scope :without_a_dog, -> {
includes(:dog).merge( Dog.where(:id => nil) )
}
end
dog.rb
class Dog < ActiveRecord::Base
belongs_to :user
end
For question 2 I think the following should work:
scope :without_a_dog include(:dog), where('dogs.id is null')
Where include should do a left join meaning that where there's no dog relation to join to the user the dogs.id column should be null.
user.rb
scope :without_a_dog, -> {
includes(:dog).select { |user| user.dog.nil? }
}
精彩评论