Rails - has_one 关系:关联和非关联对象的范围

MrR*_*uru 5 sql activerecord ruby-on-rails

我有这样的关系:一个用户可以拥有零只或一只狗,但狗必须属于某人。

# dog.rb
class Dog < ActiveRecord::Base
  belongs_to :user
end

# user.rb
class User < ActiveRecord::Base
  has_one :dog
end
Run Code Online (Sandbox Code Playgroud)

我想定义以下范围:

User.with_a_dog
User.without_a_dog
Run Code Online (Sandbox Code Playgroud)

我可以对第一种情况执行此操作,因为在 Rails 中默认连接是 INNER JOIN :

scope :with_a_dog, :joins(:dog)
Run Code Online (Sandbox Code Playgroud)

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

2/ 第二个你会做什么?

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

# user.rb
def has_a_dog?
  !self.dog.nil?
end
Run Code Online (Sandbox Code Playgroud)

感谢您的帮助!

br3*_*3nt 5

只是想添加这个以防有人发现它有用:

用户.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
Run Code Online (Sandbox Code Playgroud)

狗.rb

class Dog < ActiveRecord::Base
  belongs_to :user
end
Run Code Online (Sandbox Code Playgroud)


Chr*_*ley 1

对于问题2,我认为以下应该有效:

scope :without_a_dog include(:dog), where('dogs.id is null')
Run Code Online (Sandbox Code Playgroud)

其中 include 应该执行左连接,这意味着如果没有狗关系可以连接到用户,则 dogs.id 列应该为空。