Arrays 轨道-包括?使用对象或对象id

Arrays 轨道-包括?使用对象或对象id,arrays,ruby-on-rails,ruby,Arrays,Ruby On Rails,Ruby,我有一个名为Company的对象,它有一个名为owner的方法,返回一个用户对象数组。我想通过检查当前用户是否在所有者数组中来筛选这些公司。首先,我做了这样的事情(这很有效): 但是,我认为更有效的检查方法是只比较ID,而不是比较整个对象: Company.select { |c| c.owners.map(&:id)include?(current_user.id) } 有人能帮我理解这两个选项之间是否有区别吗?这两个选项之间确实没有区别。这两种方法都非常低效,如果你的公司桌子很大,

我有一个名为Company的对象,它有一个名为owner的方法,返回一个用户对象数组。我想通过检查当前用户是否在所有者数组中来筛选这些公司。首先,我做了这样的事情(这很有效):

但是,我认为更有效的检查方法是只比较ID,而不是比较整个对象:

Company.select { |c| c.owners.map(&:id)include?(current_user.id) }

有人能帮我理解这两个选项之间是否有区别吗?

这两个选项之间确实没有区别。这两种方法都非常低效,如果你的公司桌子很大,它们就不起作用。它们将所有公司记录加载到内存中,然后调用
c.owners
,对每个记录进行额外查询。这称为N+1查询。您可以使用
Company.all.includes(:owners)
来处理N+1部分,但仍然存在将所有内容加载到内存中的问题

很难给出准确的代码,因为您没有共享模型定义(特别是
公司#所有者
关联的定义)。但我假设您有一个公司所有者联接表。在这种情况下,我建议使用以下代码:

companies = CompanysOwners.where(owner: current_user).includes(:company).map(&:company)
这只会触发一个查询,并且不会将更多记录加载到内存中。您可以去掉
包含(:company)
部分,它仍然可以工作,但速度较慢

如果您的
公司#所有者
协会的定义与此不同,请随时发表评论,我可以向您展示如何根据您的需要修改此协会


顺便说一下,为了更直接地回答您最初的问题。。。在引擎盖下,
c.owners.include?(当前用户)
使用
=
比较记录。而
ActiveRecord::Core#=
正在比较引擎盖下的ID。您可以在此处查看源代码以证明:。所以他们真的在做同样的事情。

两者之间真的没有区别。这两种方法都非常低效,如果你的公司桌子很大,它们就不起作用。它们将所有公司记录加载到内存中,然后调用
c.owners
,对每个记录进行额外查询。这称为N+1查询。您可以使用
Company.all.includes(:owners)
来处理N+1部分,但仍然存在将所有内容加载到内存中的问题

很难给出准确的代码,因为您没有共享模型定义(特别是
公司#所有者
关联的定义)。但我假设您有一个公司所有者联接表。在这种情况下,我建议使用以下代码:

companies = CompanysOwners.where(owner: current_user).includes(:company).map(&:company)
这只会触发一个查询,并且不会将更多记录加载到内存中。您可以去掉
包含(:company)
部分,它仍然可以工作,但速度较慢

如果您的
公司#所有者
协会的定义与此不同,请随时发表评论,我可以向您展示如何根据您的需要修改此协会

顺便说一下,为了更直接地回答您最初的问题。。。在引擎盖下,
c.owners.include?(当前用户)
使用
=
比较记录。而
ActiveRecord::Core#=
正在比较引擎盖下的ID。您可以在此处查看源代码以证明:。所以他们真的在做同样的事情

我有一个名为Company的对象,它有一个名为owner的方法,返回一个用户对象数组

这就是你的问题所在

这实际上应该在模型层上通过设置:

这是非常有效的,因为它只执行一个查询来获取相关记录,而不是将整个表加载到内存中。这将返回一个
ActiveRecord::Relation
对象,而不是一个数组,该数组允许您在需要时添加其他作用域:

current_user.companies.where(bankrupt: false)
从代码设计的角度来看,它也具有优势,因为业务逻辑被封装在您的模型中,而不是到处泄漏实现细节

它还可以让您避免n+1查询:

@users = User.include(:companies)
             .all

@users.each do |user|
  # this loads all the companies in one single query instead 
  # of one query per user
  user.companies.each do |company|
    puts company.name  
  end
end
如果出于某种原因需要检查两条记录是否相关,则需要使用join和where子句:

@companies = Company.joins(:owners)
                    .where(users: { id: current_user.id })
我有一个名为Company的对象,它有一个名为owner的方法,返回一个用户对象数组

这就是你的问题所在

这实际上应该在模型层上通过设置:

这是非常有效的,因为它只执行一个查询来获取相关记录,而不是将整个表加载到内存中。这将返回一个
ActiveRecord::Relation
对象,而不是一个数组,该数组允许您在需要时添加其他作用域:

current_user.companies.where(bankrupt: false)
从代码设计的角度来看,它也具有优势,因为业务逻辑被封装在您的模型中,而不是到处泄漏实现细节

它还可以让您避免n+1查询:

@users = User.include(:companies)
             .all

@users.each do |user|
  # this loads all the companies in one single query instead 
  # of one query per user
  user.companies.each do |company|
    puts company.name  
  end
end
如果出于某种原因需要检查两条记录是否相关,则需要使用join和where子句:

@companies = Company.joins(:owners)
                    .where(users: { id: current_user.id })

谢谢你的详细解释!我提到‘owner’是一个返回数组(而不是关系)的方法(不是关联),所以include可能不起作用?它根据某些条件和查看权限创建一个数组。所以我想如果不进行重构,我就无法避免这种低效的查询了?谢谢你的详细解释!我提到‘owner’是一个返回数组(而不是关系)的方法(不是关联),所以include可能不起作用?它根据某些条件和查看权限创建一个数组。所以我想如果不进行重构,我就无法避免这种低效的查询?