Rails为多态关联激发N + 1个查询

时间:2017-03-01 05:37:21

标签: ruby-on-rails polymorphic-associations active-model-serializers

我正在使用Rails 5.0.1,我对以下问题感到困惑。我有几个具有多态关联的模型。

class Container < ApplicationRecord
  has_many :steps, as: 'parent', dependent: :destroy
end

class Step < ApplicationRecord
  belongs_to :parent, polymorphic: true
  belongs_to :implementation, polymorphic: true
end

class FirstStep < ApplicationRecord
  has_one :step, as: 'implementation'
  has_many :params, dependent: :destroy
end

class SecondStep < ApplicationRecord
  has_one :step, as: 'implementation'
  has_many :headers, dependent: :destroy
end

class Param < ApplicationRecord
  belongs_to :first_step
end

class Header < ApplicationRecord
  belongs_to :second_step
end

与实施相关联的步骤(FirstStepSecondStep)。除此之外,container也可以是step的实现。我正在使用See here将模型信息序列化为JSON。以下是序列化程序的相关代码。

class StepSerializer < ActiveModel::Serializer
  attributes :id, :implementation_type, :implementation_id, :active, :position

  belongs_to :implementation
end

class FirstStepSerializer < ActiveModel::Serializer
  attributes :name, :params_attributes

  def params_attributes
    object.params.map { |p| ParamSerializer.new(p).attributes }
  end
end

class SecondStepSerializer < ActiveModel::Serializer
  attributes :id, :title, :headers_attributes

  def headers_attributes
    object.headers.map { |p| HeaderSerializer.new(p).attributes }
  end
end

class ParamSerializer < ActiveModel::Serializer
  attributes :id
end

class HeaderSerializer < ActiveModel::Serializer
  attributes :id
end

step模型的实现可以具有不同的属性,如模型中指定的那样。问题是,当我写

render json: container.steps

它触发N + 1个查询以获得结果。我该如何优化它?

修改1

受到Active Model Serializers的启发,我试图通过implementation_type分隔对象,并且它有效。我做的是:

# my controller action
def index
  steps = []

  steps += container.steps.where(implementation_type: 'FirstStep').includes(implementation: [:params])
  steps += container.steps.where(implementation_type: 'SecondStep').includes(implementation: [:headers])

  render json: steps
end

这阻止了N + 1查询提取paramsheaders,但如果stepcontainer则无效。

1 个答案:

答案 0 :(得分:0)

更改您的FirstStepSerializerSecondStepSerializer序列化程序,如下所示

class FirstStepSerializer < ActiveModel::Serializer
  attributes :name
  has_many :params, :serializer => ParamSerializer
end

class SecondStepSerializer < ActiveModel::Serializer
  attributes :id, :title
  has_many :headers, :serializer => HeaderSerializer
end

这可能会有所帮助