Rails-包括?带有对象或对象ID

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

Company.select { |c| c.owners.include?(current_user) }

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

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

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

回答

两者其实没什么区别。两者都非常低效,如果您的 Company 表很大,则无法工作。他们将所有公司记录加载到内存中,并进一步调用c.owners它对每个记录触发附加查询。这称为 N+1 查询。您可以使用 解决 N+1 部分Company.all.includes(:owners),但您仍然会遇到将所有内容加载到内存中的问题。

由于您尚未共享模型定义(特别是Company#owners关联的定义方式),因此很难为您提供确切的代码。但我假设您有一个 CompanysOwners 连接表。在这种情况下,我会推荐以下代码:

companies = CompanysOwners.where(owner: current_user).includes(:company).map(&:company)

这只会触发单个查询,并且不会将比需要更多的记录加载到内存中。你可以去掉这个includes(:company)部分,它仍然可以工作,但速度会慢一些。

如果您的Company#owners关联定义与此不同,请随时发表评论,我可以向您展示如何根据您的需要修改它。

顺便说一句,为了更直接地解决您的原始问题......在幕后,c.owners.include?(current_user)用于==比较记录。并且ActiveRecord::Core#==正在比较引擎盖下的 ID。您可以在此处查看源代码以证明这一点:https : //api.rubyonrails.org/v6.1.3.1/classes/ActiveRecord/Core.html#method-i-3D-3D。所以他们真的在做同样的事情。


以上是Rails-包括?带有对象或对象ID的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>