You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ruby on Rails中如何遍历对象数组创建OrderDetail类新实例?

Rails订单与订单详情关联创建问题处理

问题描述

我有一个Order模型,其中包含名为item_details的对象数组。创建新订单时,需要遍历item_details数组,创建对应Order ID的OrderDetail实例。由于OrderDetail是关联表,必须在Order创建完成后才能生成实例,这样才能把order_id写入OrderDetails。目前我已经把item_details的数据类型设为json来实现数据库存储;之前用text/string类型时,会出现符号被保存为字符串的问题。

订单示例

{
    "id": 5,
    "customer_id": 1,
    "order_date": "2023-01-03",
    "total_cost": 0,
    "item_details": [
        {
            "product_id": 3,
            "quantity": 3
        },
        {
            "product_id": 9,
            "quantity": 4
        }
    ]
}

数据库Schema

create_table "order_details", force: :cascade do |t|
    t.integer "product_id"
    t.integer "order_id"
    t.integer "quantity"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
  end

  create_table "orders", force: :cascade do |t|
    t.integer "customer_id"
    t.string "order_date"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.json "item_details"
  end

模型代码

Order模型

class Order < ApplicationRecord
    belongs_to :customer
    has_many :order_details
    has_many :products, through: :order_details
end

OrderDetail模型

class OrderDetail < ApplicationRecord
    validates :quantity, numericality: { only_integer: true }
    belongs_to :order
    belongs_to :product  
end

序列化器代码

OrderSerializer

class OrderSerializer < ActiveModel::Serializer
  attributes :id, :customer_id, :order_date, :total_cost, :item_details

  belongs_to :customer
  has_many :order_details
  has_many :products

  def total_cost
    cost = []
    self.object.order_details.each do |details|
      product = self.object.products.find {|product| product.id == details.product_id}
      cost << product.price * details.quantity
    end
    return cost.sum
  end
end

OrderDetailSerializer

class OrderDetailSerializer < ActiveModel::Serializer
  attributes :id, :product_id, :order_id, :quantity, :product

  belongs_to :order
  belongs_to :product
end

控制器代码

Orders控制器

class OrdersController < ApplicationController
    wrap_parameters format: []
    skip_before_action :authorized, only: :create

    def index
        orders = Order.all
        if orders
        render json: orders
        else
            render json: {error: "未找到订单" }, status: :not_found
        end
    end

    def show
        order = Order.find_by(id: params[:id])
        if order
            render json: order
        else
            render json: { error: "未找到订单" }, status: :not_found
        end
    end

    def create
        order = Order.create(order_params)
        if order.valid?
            order.item_details.each do |i|
                OrderDetail.create(order_id: params[:id], product_id: i[:product_id], quantity: i[:quantity])
            end
            render json: order
        else
            render json: { errors: order.errors.full_messages }, status: :unprocessable_entity
        end
    end

    def update
        order = Order.find_by(id: params[:id])
        if order
            order.update(order_params)
            render json: order
        else
            render json: { error: "未找到订单" }, status: :not_found
        end
    end

    def destroy
        order = Order.find_by(id: params[:id])
        if order
            order.destroy
            head :no_content
        else
            render json: {error: "未找到订单"}, status: :not_found
        end
    end

    private

    def order_params
        params.permit(:customer_id, :order_date, item_details: [:product_id, :quantity] )
    end
end

OrderDetails控制器

class OrderDetailsController < ApplicationController
    skip_before_action :authorized, only: :create

    def index
        order_details = OrderDetail.all
        if order_details
        render json: order_details
        else
            render json: {error: "未找到记录"}, status: :not_found
        end
    end

    def create
        order_detail = OrderDetail.create(order_details_params)
        if order_detail.valid?
            render json: order_detail
        else
            render json: { errors: order_detail.errors.full_messages }, status: :unprocessable_entity
        end
    end

    def update
        order_detail = OrderDetail.find_by(id: params[:id])
        if order_detail
            order_detail.update(order_details_params)
            render json: order_detail
        else
            render json: { error: "未找到记录" }, status: :not_found
        end
    end

    private

    def order_details_params
        params.permit(:order_id, :product_id, :quantity)
    end
end

关键问题修正提示

注意到OrdersController的create方法中,创建OrderDetail时使用了params[:id],这是错误的——刚创建的order实例的ID应该用order.id,params[:id]此时还不存在。修正后的create方法如下:

def create
    order = Order.create(order_params)
    if order.valid?
        order.item_details.each do |i|
            OrderDetail.create(order_id: order.id, product_id: i[:product_id], quantity: i[:quantity])
        end
        render json: order
    else
        render json: { errors: order.errors.full_messages }, status: :unprocessable_entity
    end
end

另外,既然已经通过OrderDetail关联订单和商品,Order模型中的item_details字段其实可以不需要存储,因为关联数据已经保存在order_details表中,避免数据冗余。可以考虑移除orders表中的item_details字段,直接从请求参数中获取商品详情来创建OrderDetail实例。


内容的提问来源于stack exchange,提问作者angiem103

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 07:11:07