渴望与Active Model Serializers加载关联

Rya*_*yan 14 performance ruby-on-rails associations eager-loading active-model-serializers

背景

我有一个带有深层嵌套关联的rails应用程序.

                          .-< WorkPeriod
Timecard -< Week -< Day -<--< Subtotal
                          `-< Adjustment

-<  (has many)
Run Code Online (Sandbox Code Playgroud)

我正在使用Active Model Serializer来构建API.

在客户端,我想一次性加载时间卡和所有关联.

目前我的序列化器看起来像这样,

class TimecardSerializer < ActiveModel::Serializer
  embed :ids, include: true
  has_many :weeks
end
class WeekSerializer < ActiveModel::Serializer
  embed :ids, include: true
  has_many :days
end
# ... etc ...
Run Code Online (Sandbox Code Playgroud)

问题

这一切都找到了,除了没有什么急于加载.因此,它最终会针对每个请求对数据库进行大量调用.对于每周,它会单独请求该周的日期.并且对于每一天,它单独请求它的work_periods,小计和调整.

Rya*_*yan 9

一种解决方案是weeks在TimecardSerializer上定义自己的方法.从那里你可以.includes()得到你想要加载的所有关联.

class TimecardSerializer < ActiveModel::Serializer
  embed :ids, include: true
  has_many :weeks

  def weeks
    object.weeks.includes(days: [:sub_totals, :work_periods, :adjustments])
  end
end
Run Code Online (Sandbox Code Playgroud)

所有查询仍将显示在日志中,但大多数将是缓存查询而不是真实查询.

  • 这对于加载单个资源来说很好,但如果这个序列化器用于返回“Timecard”列表,则不起作用。特别是,尽管“weeks”关联会被急切加载,但“weeks”不会被急切地加载。 (2认同)

Jam*_*mes 8

我有类似的问题.我把它固定在我的控制器里.我喜欢把它放在序列化器中的想法,但是在控制器中使用它会捕获由ArraySerializer创建的n + 1周问题.

Timecard.find(params[:id]).includes(weeks: [{ days: [:sub_totals, :work_periods, :adjustments] }])
Run Code Online (Sandbox Code Playgroud)

Timecard.includes(weeks: [{ days: [:sub_totals, :work_periods, :adjustments] }])
Run Code Online (Sandbox Code Playgroud)

现在应该急于加载并将查询限制为仅6个db命中.