渴望的负载取决于Ruby on Rails中的关联类型 [英] Eager Load Depending on Type of Association in Ruby on Rails

查看:77
本文介绍了渴望的负载取决于Ruby on Rails中的关联类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个多态关联(belongs_to :resource, polymorphic: true),其中resource可以是各种不同的模型.为了简化问题,假设它可以是OrderCustomer.

I have a polymorphic association (belongs_to :resource, polymorphic: true) where resource can be a variety of different models. To simplify the question assume it can be either a Order or a Customer.

如果它是Order,我想预加载订单,然后预加载Address.如果是客户,我想预加载Customer并预加载Location.

If it is a Order I'd like to preload the order, and preload the Address. If it is a customer I'd like to preload the Customer and preload the Location.

使用这些关联的代码执行以下操作:

The code using these associations does something like:

<%- @issues.each do |issue| -%>
<%- case issue.resource -%>
<%- when Customer -%>
<%= issue.resource.name %> <%= issue.resource.location.name %>
<%- when Order -%>
<%= issue.resource.number %> <%= issue.resource.address.details %>
<%- end -%>

当前我的预载使用:

@issues.preload(:resource)

但是,在加载条件关联时,我仍然看到n + 1问题:

However I still see n-plus-one issues for loading the conditional associations:

SELECT "addresses".* WHERE "addresses"."order_id" = ...
SELECT "locations".* WHERE "locations"."customer_id" = ...
...

什么是解决此问题的好方法?可以手动预加载关联吗?

What's a good way to fix this? Is it possible to manually preload an association?

推荐答案

您可以在ActiveRecord::Associations::Preloader类的帮助下进行此操作.这是代码:

You can do that with the help of ActiveRecord::Associations::Preloader class. Here is the code:

@issues = Issue.all # Or whatever query
ActiveRecord::Associations::Preloader.new.preload(@issues.select { |i| i.resource_type == "Order" }, { resource: :address })
ActiveRecord::Associations::Preloader.new.preload(@issues.select { |i| i.resource_type == "Customer" }, { resource: :location })

过滤集合时可以使用其他方法.例如,在我的项目中,我正在使用group_by

You can use different approach when filtering the collection. For example, in my project I am using group_by

groups = sale_items.group_by(&:item_type)
groups.each do |type, items|
  conditions = case type
  when "Product" then :item
  when "Service" then { item: { service: [:group] } }
end

ActiveRecord::Associations::Preloader.new.preload(items, conditions)

您可以轻松地将此代码包装在一些帮助程序类中,并在应用程序的不同部分中使用它.

You can easily wrap this code in some helper class and use it in different parts of your app.

这篇关于渴望的负载取决于Ruby on Rails中的关联类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆