渴望的负载取决于Ruby on Rails中的关联类型 [英] Eager Load Depending on Type of Association in Ruby on Rails
问题描述
我有一个多态关联(belongs_to :resource, polymorphic: true
),其中resource
可以是各种不同的模型.为了简化问题,假设它可以是Order
或Customer
.
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屋!