Rails - has_one关联:关联和非关联对象的作用域

5
我有这样一个关系:用户可以拥有零只或一只狗,但是一只狗必须属于某个人。
# dog.rb
class Dog < ActiveRecord::Base
  belongs_to :user
end

# user.rb
class User < ActiveRecord::Base
  has_one :dog
end

我想定义以下范围:
User.with_a_dog
User.without_a_dog

我可以为第一个案例做这件事,因为在Rails中默认情况下连接是内部连接:

scope :with_a_dog, :joins(:dog)

1/ 这个解决方案对于第一个范围是否足够好?

2/ 对于第二个范围,你会怎么做?

3/ (有点相关)还有更好的方法吗?:

# user.rb
def has_a_dog?
  !self.dog.nil?
end

感谢您的帮助!

1
应该是 scope with_a_dog, joins(:dog) 不需要冒号。 - Richard
3个回答

5

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

1

对于问题2,我认为以下代码应该是可行的:

scope :without_a_dog include(:dog), where('dogs.id is null')

include 应该执行左连接,这意味着如果没有与用户关联的狗,则 dogs.id 列应为 null。


无法在Rails 3.2上工作,但以下代码解决了问题:scope :without_profile, lambda { includes(:user_profile).where('user_profiles.id is null') } - yorch

1

user.rb

scope :without_a_dog, -> {
    includes(:dog).select { |user| user.dog.nil? }
  }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接