Rails 不返回特定模型的生成 ID
Posted
技术标签:
【中文标题】Rails 不返回特定模型的生成 ID【英文标题】:Rails not returning generated ID for specific model 【发布时间】:2021-12-29 20:19:06 【问题描述】:我最近开始维护几个带有 PostgreSQL 后端的 Rails 5.2 应用程序。我是 Rails 新手,但在各种 Microsoft 平台上都有相当多的经验。
我正在尝试将 API 调用添加到现有模型。当我尝试创建一个新实例时,我没有取回数据库生成的 ID:
POST /invoices
"amount": 12.34
Invoice Create (4.0ms)
INSERT INTO "invoices" ("amount", "created_at", "updated_at")
VALUES ($1, $2, $3)
[["amount", 12.34], ["created_at", "..."], ["updated_at", "..."]]
201 Created
"id": null, "amount": 12.34
检查数据库,新行存在,具有唯一 ID。
同一应用中的不同模型生成不同的 SQL 并按预期工作:
POST /customer
"name": "ACME"
Customer Create (1.4ms)
INSERT INTO "customers" ("name", "created_at", "updated_at")
VALUES ($1, $2, $3)
** RETURNING "id" **
[["name", "ACME"], ["created_at", "..."], ["updated_at", "..."]]
201 Created
"id": 111, "name": "ACME"
我看不出解释这种行为的两个模型有什么不同。我已经检查了我能想到的所有内容:
路线(通过 :resources) 控制器 过滤器之前/之后 强大的参数 代码在create
型号
都不包含任何代码
架构
schema.rb 和 information_schema.columns 中的列定义具有可比性
这是行为不端类型的模型和控制器:
class Invoice < ActiveRecord::Base
end
class InvoiceController < ApplicationController
def create
invoice = Invoice.new(invoice_params)
if invoice.save
# invoice.id.nil? => true
render json: invoice, status: :created
end
end
def invoice_params
params.permit(:amount)
end
end
# schema.rb
create_table "invoices", id: false, force: :cascade do |t|
t.serial "id", null: false
t.float "amount"
t.datetime "created_at"
t.datetime "updated_at"
end
还有一个按预期工作的:
class Customer < ActiveRecord::Base
end
class CustomerController < ApplicationController
def create
customer = Customer.new(customer_params)
if customer.save
# customer.id.nil? => false
render json: customer, status: :created
end
end
def customer_params
params.permit(:name)
end
end
# schema.rb
create_table "customers", id: :serial, force: :cascade do |t|
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
end
将new
/save
替换为create
或create!
不会改变行为,因此我确信问题出在模型定义或元数据的某个地方。
从rails console
创建模型的结果相同,如下所示:
irb(main):001:0> Invoice.create(amount:12.34)
(0.8ms) BEGIN
Invoice Create (1.1ms) INSERT INTO "invoices" ("amount", "created_at", "updated_at") VALUES ($1, $2, $3) [["amount", 12.34], ["created_at", "2021-11-19 09:10:33.490117"], ["updated_at", "2021-11-19 09:10:33.490117"]]
(5.8ms) COMMIT
=> #<Invoice id: nil, amount: 12.34, created_at: "2021-11-19 09:10:33", updated_at: "2021-11-19 09:10:33">
irb(main):002:0> Customer.create(name: "ACME")
(0.9ms) BEGIN
Customer Create (1.5ms) INSERT INTO "customers" ("name", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id" [["name", "ACME"], ["created_at", "2021-11-19 09:12:50.492927"], ["updated_at", "2021-11-19 09:12:50.492927"]]
(13.3ms) COMMIT
=> #<Customer id: 24, name: "ACME", created_at: "2021-11-19 09:12:50", updated_at: "2021-11-19 09:12:50">
谁能指出我正确的方向?
【问题讨论】:
你需要发布模型代码,其中必须有代码,即使只是一个类声明,也请控制器动作 感谢@jamesc,我已经更新了帖子。我应该说模型只包含类声明:) 你有哪些 JSON 模板?在视图文件夹中 如果您只想要模型中的原始 jsin,那么您的操作可以返回对象 to_json 但您可能正在模板中格式化响应,这 8s 通常在 response_to 块中返回 现在,这些模型的视图文件夹中什么都没有。原来有一个show.json.builder 没有包含id,但是添加后并没有解决问题,所以我改成render json:
如上图。
【参考方案1】:
不同之处在于您将“id”显式声明为列,并禁用了默认主键“id”声明/处理。
如果你改为:
create_table "invoices", id: :serial, force: :cascade do |t|
t.float "amount"
# These are normally created automatically so not sure why they are here
# t.datetime "created_at"
# t.datetime "updated_at"
end
它应该可以工作。
这个答案也可能有帮助:https://***.com/a/54694863/224837
【讨论】:
【参考方案2】:这是由于相关表中缺少主键造成的。看起来这些表可能是在项目早期的某个时候手动创建的,并且直到现在才被外部 SQL 脚本写入。
【讨论】:
以上是关于Rails 不返回特定模型的生成 ID的主要内容,如果未能解决你的问题,请参考以下文章