- 更新 - Rails API 应用程序使用来自控制器的 POST 请求一次创建不同模型的多个嵌套记录
Posted
技术标签:
【中文标题】- 更新 - Rails API 应用程序使用来自控制器的 POST 请求一次创建不同模型的多个嵌套记录【英文标题】:- UPDATED - Rails API app create multiple nested records of a different models at once using POST request from the controller 【发布时间】:2021-09-30 16:39:27 【问题描述】:我正在开发一个 API Ruby on 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
这是我对 http://localhost:3000/api/create_custon_plan
的 POST 请求正文
"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"
]
]
到目前为止,嵌套日工作正常,但嵌套日内的嵌套餐不知道如何解决这个问题?甚至终端内的日志也完全忽略它
【问题讨论】:
你能不能试着打印出day.valid?
,还有像before_save
这样的模型中有回调吗?
这有点不相关,但您应该将所有逻辑从控制器转移到模型中,该代码非常难以阅读,它在 JSON 响应中有很多条件和重复代码。您可能会受益于在 Active Record 事务块中编写所有内容,如果其中一个子对象插入失败,您可以回滚所有插入。
【参考方案1】:
您无需循环访问它们并单独创建它们。 Plan.new(plan_params)
应该可以完成这项工作,您只需要正确指定嵌套属性即可。
变化:
days
到 day_attributes
不需要传递 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
【讨论】:
感谢您提供详细信息,但是我似乎在这里做错了,因为第 3 级没有保存,如果我在这里的示例,计划和日期按预期完美保存,但是第三级“餐”被控制台和json响应完全忽略,它总是一个空数组,有什么想法吗? 也许你可以看看表之间的关系应该是怎样的,因为我做了一些改变来优化数据库,class Plan < ApplicationRecord has_and_belongs_to_many :days has_and_belongs_to_many :meals accepts_nested_attributes_for :meals accepts_nested_attributes_for :days end
,class Day < ApplicationRecord has_and_belongs_to_many :days has_and_belongs_to_many :meals end
,class Meal < ApplicationRecord has_and_belongs_to_many :days has_and_belongs_to_many :meals end
尝试将accepts_nested_attributes_for :meals
从plan.rb
移动到day.rb
你也可以参考 railscasts 的第 196 集,你会发现同样的例子。在上面添加了一个链接。
我尝试了很多其他方法,但没有任何效果,我正在检查 rails cast 剧集,也许它会有所帮助以上是关于- 更新 - Rails API 应用程序使用来自控制器的 POST 请求一次创建不同模型的多个嵌套记录的主要内容,如果未能解决你的问题,请参考以下文章
Rails API 用户身份验证接受来自 React 代理的 api 调用,但不直接来自主机 url
根据我在 rails/react 应用程序上的 api 调用状态更新我的视图