- 更新 - Rails API 应用程序使用来自控制器的 POST 请求一次创建不同模型的多个嵌套记录

- UPDATED - Rails API app create multiple nested records of a different models at once using POST request from the controller

我正在 API Ruby rails 6.1 应用程序上工作,所以我的所有回复都在 JSON 中。我正在尝试创建一个 3 级嵌套记录,这意味着我想创建一个计划记录,其中包含许多天的记录,其中包含每天的许多餐点。

Plan.rb

class Plan < ApplicationRecord
    has_and_belongs_to_many :days
    has_and_belongs_to_many :meals
    has_one_attached :image, dependent: :destroy
    accepts_nested_attributes_for :meals, reject_if: ->(object) { object[:name].blank? }
    accepts_nested_attributes_for :days, reject_if: ->(object) { object[:number].blank? }
end

Day.rb

class Day < ApplicationRecord
     has_and_belongs_to_many :plans
     has_and_belongs_to_many :meals
     validates_presence_of :number, on: [:create, :update], message: "can't be blank"
     validates_uniqueness_of :number, on: [:create, :update], message: "You can't use same day number twice"
     accepts_nested_attributes_for :meals, reject_if: ->(object) { object[:name].blank? }
end

Meal.rb

class Meal < ApplicationRecord
  has_and_belongs_to_many :days
  has_and_belongs_to_many :plans
end

我还添加了 2 个连接表

  create_table "days_meals", id: false, force: :cascade do |t|
     t.bigint "day_id", null: false
     t.bigint "meal_id", null: false
  end

  create_table "days_plans", id: false, force: :cascade do |t|
     t.bigint "day_id", null: false
     t.bigint "plan_id", null: false
  end

这是plans_controller.rb

中的UPDATED方法
# POST /create_custon_plan
 def create_custon_plan
    @plan = Plan.new(plan_params)

    if @plan.save
      render json: {
        messages: "Plan was successfully created.",
        is_success: true,
        status: :created,
        data: { plan: @plan, days_attributes: @plan.days, meals_attributes: @plan.meals },
      }
    else
      render json: @plan.errors, status: :unprocessable_entity
    end
  end

这就是我允许我的参数的方式

def plan_params
    params.require(:plan).permit(:name, :monthly_price, :image_url, days_attributes: [:number, meals_attributes: [:name, :calories, :protein, :fat, :carbohydrates, :categorie]])
end

这是我的 POST 请求正文 http://localhost:3000/api/create_custon_plan

{
    "name": "Test Plan",
    "monthly_price": 0,
    "image_url": "55555",
    "days_attributes": [
                {
                "number": 500,
                "meals_attributes": [
                            {
                                "name": "azerazer Salad",
                                "calories": 55,
                                "protein": 55,
                                "fat": 55,
                                "carbohydrates": 55,
                                "image_url": "55555",
                                "categorie": "snack-1"
                            },
                            {
                                "name": "Fit Burger",
                                "calories": 55,
                                "protein": 55,
                                "fat": 55,
                                "carbohydrates": 55,
                                "image_url": "55555",
                                "categorie": "meal-1"
                            },
                            {
                                "name": "Vegan Rataouille",
                                "calories": 55,
                                "protein": 55,
                                "fat": 55,
                                "carbohydrates": 55,
                                "image_url": "55555",
                                "categorie": "snack-2"
                            },
                            {
                                "name": "Chicken BBQ",
                                "calories": 55,
                                "protein": 55,
                                "fat": 55,
                                "carbohydrates": 55,
                                "image_url": "55555",
                                "categorie": "meal-3"
                            }
                        ]
                },
                {
                "number": 502,
                "meals_attributes": 
                        [
                            {
                                "name": "Woldrof Salad",
                                "calories": 55,
                                "protein": 55,
                                "fat": 55,
                                "carbohydrates": 55,
                                "image_url": "55555",
                                "categorie": "snack-1"
                            },
                            {
                                "name": "Baked Beef",
                                "calories": 55,
                                "protein": 55,
                                "fat": 55,
                                "carbohydrates": 55,
                                "image_url": "55555",
                                "categorie": "meal-1"
                            }
                        ]
                }
            ]
}

到目前为止,嵌套日工作正常,但嵌套日内的嵌套膳食不知道如何解决?甚至终端内的日志也完全忽略它

您无需循环访问它们并单独创建它们。 Plan.new(plan_params) 应该可以完成工作,您只需正确指定嵌套属性即可。

变化:

  1. daysday_attributes
  2. 不需要传递 ID。

例如:

{
"name": "Test Plan",
"monthly_price": 0,
"image_url": null,
"day_attributes": [
            {
            "number": 1,
            "meal_attributes": [
                        {
                            "name": "Kale Salad",
                            "calories": null,
                            "protein": null,
                            "fat": null,
                            "carbohydrates": null,
                            "image_url": null,
                            "categorie": "snack-1"
                        },
                        {
                            "name": "Fit Burger",
                            "calories": null,
                            "protein": null,
                            "fat": null,
                            "carbohydrates": null,
                            "image_url": null,
                            "categorie": "meal-1"
                        },
                        {
                            "name": "Vegan Rataouille",
                            "calories": null,
                            "protein": null,
                            "fat": null,
                            "carbohydrates": null,
                            "image_url": null,
                            "categorie": "snack-2"
                        },
                        {
                            "name": "Chicken BBQ",
                            "calories": null,
                            "protein": null,
                            "fat": null,
                            "carbohydrates": null,
                            "image_url": null,
                            "categorie": "meal-3"
                        }
                    ]
            },
            {
            "number": 2,
            "meal_attributes": 
                    [
                        {
                            "name": "Woldrof Salad",
                            "calories": null,
                            "protein": null,
                            "fat": null,
                            "carbohydrates": null,
                            "image_url": null,
                            "categorie": "snack-1"
                        },
                        {
                            "name": "Baked Beef",
                            "calories": null,
                            "protein": null,
                            "fat": null,
                            "carbohydrates": null,
                            "image_url": null,
                            "categorie": "meal-1"
                        }
                    ]
            }
        ]

}

此外,您还应该在许可参数中适当提及它们,例如:

params.permit(:name, :monthly_price, :image_url, day_attributes: [:number, meal_attributes: [:name, :calories, :protein, :fat, :carbohydrates, :image_url, :categorie]])

更多信息可以参考:

Active Record Nested Attributes

Railscasts #196