0

我正在使用Rails 5.0.1,並對以下問題感到困惑。我很少有多態關聯的模型。Rails觸發多態關聯的N + 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的實現。我正在使用Active Model Serializers將模型信息序列化爲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

通過this answer啓發,我試圖通過他們的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這是行不通的。

回答

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 

這可能有助於

+0

這仍然觸發N + 1個查詢,因爲'object.implementation'的'params'和'headers'無法加載預先。 – 31piy