如何在另一个序列化器中使用模型的实例

how to use an instance of a model in another serializer

我被困在这里,找不到解决方案来继续我的工作,

我有 3 个模型:计划、日期和膳食。

这是我的 Plan Controller 我已经设法在控制器中得到正确的答案,我希望它嵌套在序列化程序中,因为我正在使用 URL 助手来检索我的图像 URLs,有没有办法在 DaySerializer 中使用 @plan.id

  def meals
    @plan = Plan.find(params[:id])
    @days = @plan.days
    @meals = Meal.where("plan_id = ? ", @plan.id)
    render :json => { :plan => @plan, :days => @days,
                      :meals => @meals }
  end

这是我的计划模型

class Plan < ApplicationRecord
  has_many :days
  has_one_attached :image, dependent: :destroy
end

这是我的 Day 模型

class Day < ApplicationRecord
  has_many :meals
  has_many :plans
end

这是我的膳食模型

class Meal < ApplicationRecord
  belongs_to :plan
  belongs_to :day
  has_one_attached :image, dependent: :destroy
end

我想显示特定计划的所有膳食,为此我需要在 daySerializer 中使用一个变量,但我找不到如何做。

这是我的 planSerializer

class PlanSerializer < ActiveModel::Serializer
  attributes :id, :name, :monthly_price, :plan_days

  def plan_days
    object.days.map do |day|
      DaySerializer.new(day, scope: scope, root: false, event: object)
    end
  end
end

这是我的 DaySerializer,我需要在里面使用计划的实例

class DaySerializer < ActiveModel::Serializer
  attributes :number, :plan_meals

  def plan_meals
    #how to be able to use this line in Serilizer? !important
    @plan = Plan.find(params[:id])
    object.meals.map do |meal|
      if meal.plan_id == @plan.id
        MealSerializer.new(meal, scope: scope, root: false, event: object)
      end
    end
  end
end

目标原因回复:

{
  id: 8,
  name: "Plan1",
  monthly_price: 88,
  plan_days: [
    {
      number: 5,
      plan_meals: [],
    },
    {
      number: 4,
      plan_meals: [],
    },
    {
      number: 3,
      plan_meals: [],
    },
    {
      number: 2,
      plan_meals: [],
    },
    {
      number: 1,
      plan_meals: [
        {
          id: 11,
          name: "test meal",
          calories: 32,
          protein: 32,
          fat: 32,
          carbohydrates: 32,
          plan_id: 8,
        },
      ],
    },
  ],
}

目前显示属于每一天的所有膳食,

不仅是与plan_id = Plan.find(params[:id])

的饭菜

更新: 添加膳食序列化程序如何?

class MealSerializer < ActiveModel::Serializer
  attributes :id, :name, :calories, :protein, :fat, # etc
end
class DaySerializer < ActiveModel::Serializer
  attributes :number
  has_many :meals, serializer: MealSerializer
end

原文:

class PlanSerializer < ActiveModel::Serializer
  attributes :id, :name, :monthly_price, :plan_days
  
  has_many :plan_days, serializer: DaySerializer
end

像这样。

总的来说,我认为你可以使用类似这样的东西。

ActiveModel::Serializer::CollectionSerializer.new。实际上,它本身允许您将附加信息传递给您的序列化程序。它与您当前的代码一样,只是您能够显式传递新数据。

控制器:

  def meals
    @plan = Plan.find(params[:id])
    @days = @plan.days
    @meals = Meal.where("plan_id = ? ", @plan.id)
    render :json => { 
      :plan => @plan,
      :days => ActiveModel::Serializer::CollectionSerializer.new(@days, serializer: DaySerializer, plan_id: @plan.id),
      :meals => @meals
    }
  end

然后在DaySerializer:

class DaySerializer < ActiveModel::Serializer
  attributes :number, :plan_meals

  def plan_meals
    object.meals.map do |meal|
      if meal.plan_id == instance_options[:plan_id]
        MealSerializer.new(meal, scope: scope, root: false, event: object)
      end
    end
  end
end

所以简而言之,在控制器中 ActiveModel::Serializer::CollectionSerializer.new 和在序列化器中 instance_options 以访问传递的附加参数。