这个有点令人困惑。
我认为有问题的一行是在控制器中,特别是这一行:
recipe_tools = (recipe.recipe_tools + RecipeTool.generic)
我的模特:
class Recipe < ActiveRecord::Base
...
has_many :recipe_tools, dependent: :destroy
...
end
class RecipeTool < ActiveRecord::Base
belongs_to :story
end
class Story < ActiveRecord::Base
...
has_many :recipe_tools, dependent: :destroy
..
end
这是我的控制者:
module Api
module Recipes
class RecipeToolsController < Api::BaseController
before_filter :set_cache_buster
def index
# expires_in 30.minutes, public: true
recipe = Recipe.find(params[:recipe_id])
recipe_tools = (recipe.recipe_tools + RecipeTool.generic)
binding.pry
render json: recipe_tools, each_serializer: Api::V20150315::RecipeToolSerializer
end
end
end
end
这是我的序列化器:
module Api
module V20150315
class RecipeToolSerializer < ActiveModel::Serializer
cached
delegate :cache_key, to: :object
attributes :id,
:display_name,
:images,
:display_price,
:description,
:main_image,
:subtitle
def display_name
object.display_name
end
def images
object.story.get_spree_product.master.images
end
def display_price
object.story.get_spree_product.master.display_price
end
def description
object.story.description
end
def main_image
object.story.main_image
end
def subtitle
object.story.get_spree_product.subtitle
end
def spree_product
binding.pry
spree_product.nil? ? nil : spree_product.to_hash
end
private
def recipe_tool_spree_product
@spree_product ||= object.story.get_spree_product
end
end
end
end
这是我的RecipeTool模型:
class RecipeTool < ActiveRecord::Base
...
scope :generic, -> { where(generic: true) }
end
在控制器中,我们只调用recipe.recipe_tool一次,所以我认为我们不需要包含recipe_tool。我们没有遍历一组食谱并在每个食谱上调用recipe_tool,因此没有N + 1问题。
但是,我们通过将两个recipe_tools集合连接在一起,在控制器中创建recipe_tools集合。 Recipe.generic也是一个生成通用recipe_tools的SQL查询。
我认为在通过序列化程序生成JSON响应时会发生N + 1问题。我们多次调用recipe_tool.story,每次调用#story时都会生成SQL查询,我们会在recipe_tools的集合上执行此操作。
答案 0 :(得分:0)
首先,我会使用:inverse_of修复你的关联,这样我就不必担心如果它碰巧回溯到父对象,就会重新加载rails。即
class Recipe < ActiveRecord::Base
...
has_many :recipe_tools, dependent: :destroy, :inverse_of=>:recipe
...
end
class RecipeTool < ActiveRecord::Base
belongs_to :story, :inverse_of => :recipe_tools
belongs_to :recipe, :inverse_of => :recipe_tools ## this one was missing???
end
class Story < ActiveRecord::Base
...
has_many :recipe_tools, dependent: :destroy, :inverse_of=>:story
..
end
接下来,我将eager_load控制器中的相应关联,如:
ActiveRecord::Associations::Preloader.new.preload(recipe_tools, :story =>:recipe_tools, :recipe=>:recipe_tools)
在调用序列化程序之前。