Ruby on Rails中如何将对象数组存入Order表的item_details字段
问题
我有一个Order表,其中包含item_details字段,希望该字段的值为对象数组。目前请求能成功提交,但返回的item_details是类似"{\"product_id\"=>1, \"quantity\"=>2}"的字符串而非实际对象,请问该如何修复?
相关代码及请求、返回结果:
Order Controller
class OrdersController < ApplicationController skip_before_action :authorized, only: :create def index orders = Order.all if orders render json: orders else render json: {error: "Order Not Found" }, status: :not_found end end def show order = Order.find_by(id: params[:id]) if order render json: order else render json: { error: "Order Not Found" }, status: :not_found end end def create order = Order.create(order_params) render json: order, status: :created end def update order = Order.find_by(id: params[:id]) if order order.update(order_params) render json: order else render json: { error: "Order Not Found" }, status: :not_found end end private def order_params params.permit(:customer_id, :order_date,{ item_details: [:product_id, :quantity] }) end end
Order Serializer
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
Schema
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.text "item_details", default: [], array: true end
Postman请求
{ "customer_id": 1, "order_date": 1, "item_details": [ { "product_id": 1, "quantity" : 2 }, { "product_id": 7, "quantity" : 1 } ] }
Postman返回结果
{ "id": 2, "customer_id": 1, "order_date": "1", "total_cost": 0, "item_details": [ "{\"product_id\"=>1, \"quantity\"=>2}", "{\"product_id\"=>7, \"quantity\"=>1}" ], "customer": { "id": 1, "name": "John Smith", "phone_number": "(811) 833 2172", "email": "john@yahoo.com", "address": "334 Jacobs Plaza, West Robtport, IN 26209-0933", "username": "john103", "password": null }, "order_details": [], "products": [] }
不清楚为什么哈希会以这种字符串形式呈现,而非实际对象?
解决方案
1. 修改数据库字段类型为JSONB数组
当前Schema中item_details是text类型数组,Rails无法识别哈希结构,只能将其转为Ruby字符串格式存储。需要改成JSONB类型数组,让数据库原生支持JSON对象/数组的存储与解析:
生成迁移文件:
rails generate migration ChangeItemDetailsToJsonbArrayInOrders
编辑迁移文件内容:
class ChangeItemDetailsToJsonbArrayInOrders < ActiveRecord::Migration[7.0] def change remove_column :orders, :item_details add_column :orders, :item_details, :jsonb, default: [], array: true end end
执行迁移:
rails db:migrate
2. 配置模型序列化(可选)
在app/models/order.rb中添加序列化配置,确保Rails自动处理哈希与JSON的转换:
class Order < ApplicationRecord serialize :item_details, JSON end
3. 验证修复效果
重新提交Postman请求,此时返回的item_details会是正常的对象数组:
{ "id": 3, "customer_id": 1, "order_date": "1", "total_cost": 0, "item_details": [ {"product_id": 1, "quantity": 2}, {"product_id": 7, "quantity": 1} ], // ...其他字段 }
原因说明
text数组类型仅能存储字符串,Rails会把传入的哈希直接转为Ruby哈希的字符串表示(即inspect方法的输出格式)。- JSONB是PostgreSQL原生支持的JSON类型,可直接存储JSON结构,Rails会自动完成哈希与JSON格式的双向转换,无需手动处理字符串解析。
内容的提问来源于stack exchange,提问作者angiem103
相关产品推荐
相关产品推荐

