【问题标题】:Retrieve objects that don't have a relationship in ActiveRecord/Rails在 ActiveRecord/Rails 中检索没有关系的对象
【发布时间】:2013-08-14 21:40:59
【问题描述】:

我需要从我的数据库中获取所有非员工用户:

class User < ActiveRecord::Base
  has_one :staff
  def is_staff?
    staff != nil
  end
end
class Staff < ActiveRecord::Base
  attr_accessible :user_id
  belongs_to :user
end

所以我可以在代码中做到这一点:

User.all.select {|user| not user.is_staff? }

这似乎可行,但我想在数据库中有这个逻辑,而且我在尝试以这种方式排序时由于某种原因在使用 Heroku 的生产中出错(使用 sqlite 的开发人员不会给我这个错误) :

NAME_SORT = ->(a, b) {
  if a.first_name == b.first_name
    a.last_name <=> b.last_name
  else
    a.first_name <=> b.first_name
  end
}
User.all.select {|user| not user.is_staff? }.sort &NAME_SORT

由于某种原因我得到的错误是:

ArgumentError: comparison of User with User failed

无论如何,如果我想获得所有员工用户,这似乎很简单:

User.joins(:staff)

有没有一种简单的方法可以吸引非员工用户?也许是这样的?

User.not_joins(:staff)

而且我真的需要用户不是员工或管理员:

User.not_joins(:staff, :admin)

【问题讨论】:

  • 使用User.includes(:staff).where(staff: {id: nil}) 获取所有没有人员关联的用户(您可能需要将 were 子句中的人员关系重命名为其复数版本)
  • @MrYoshiji - 很有趣,所以includes 包括非员工用户,而joins 不包括。谢谢,你应该把这个作为答案
  • 当您使用包含并使用您在 where 中包含的内容时,您执行 LEFT JOIN,而连接执行 INNER JOIN。

标签: ruby-on-rails activerecord ruby-on-rails-3.2 ruby-on-rails-4 rails-activerecord


【解决方案1】:

要获取所有与员工没有关系的用户,您可以使用以下方法:

User.includes(:staff).where(staff: { id: nil }) 

以下查询“获取所有没有关联用户的员工”的工作方式相同:

Staff.includes(:user).where(users: { id: nil })
                   ^            ^

须知:includes(以及preloadjoins)方法中,您必须使用模型中定义的关系名称(belongs_to & has_one :singularize,has_many:pluralize),但是在 where 子句中你必须使用复数形式的关系(实际上是表的名称)。

【讨论】:

    【解决方案2】:

    您有 3 个解决方案:

    • 做一些没有优化和肮脏的事情,比如:

      User.where('id NOT IN(?)', Staff.select(:user_id).all.map(&:user_id).uniq).all
      

    或者像Yoshiji先生说的

        User.includes(:staff).where(:staff => {:id => nil})
    
    • 为您的表用户添加一个字段,以了解您的用户是否有员工,因此您必须在为用户创建员工后将此字段设置为 true,但您可以轻松获取所有用户

      User.where(:have_staff => false).all
      
    • 或者你颠倒你的关系,说员工 has_one User 和 User belongs_to Staff 并得到你做的所有用户

      User.where(:staff_id => nil).all
      

    【讨论】:

    • 谢谢。我喜欢@MrYoshiji 的回答,在我的情况下,最后两个选项是不可能的
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-10-19
    • 2015-06-03
    • 1970-01-01
    • 1970-01-01
    • 2021-12-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多