【问题标题】:How to prevent rails from inserting `id: :integer` in schema.rb when creating a table?创建表时如何防止rails在schema.rb中插入`id::integer`?
【发布时间】:2018-01-24 03:20:11
【问题描述】:

最近我开始在创建新记录时遇到某些模型的错误:

PG::NotNullViolation:错误:“id”列中的空值违反 非空约束

并非所有型号都会发生这种情况,但只会发生其中一些,而且并不总是立即发生。经过一番检查后,我意识到当 'id: :integer' 出现在表创建行的 schema.rb 文件中时出现错误。

这是一个创建无错误表的迁移示例:

class CreateArticles < ActiveRecord::Migration[5.0]
  def change
    create_table :articles do |t|
      t.string :main_title
      t.boolean :published
      t.string :short_title
      t.text :a_body
      t.string :a_image

      t.timestamps
    end
  end
end

这就是 schema.rb 中显示的内容:

create_table "articles", force: :cascade do |t|
  t.string   "main_title"
  t.boolean  "published"
  t.string   "short_title"
  t.text     "a_body"
  t.string   "a_image"
  t.datetime "created_at",         null: false
  t.datetime "updated_at",         null: false
  t.string   "slug"
  t.string   "a_meta_title"
  t.string   "a_meta_description"
  t.string   "a_other"
  t.string   "a_comment"
  t.index ["slug"], name: "index_articles_on_slug", using: :btree
end

现在对“代理”做了同样的事情:

class CreateAgents < ActiveRecord::Migration[5.0]
  def change
    create_table :agents do |t|
      t.boolean :status
      t.string :stripeId
      t.integer :UserID

      t.timestamps
    end
  end
end

但是 schema.rb 文件的结果部分看起来不同:

create_table "agents", id: :integer, force: :cascade do |t|
  t.boolean  "status"
  t.string   "stripeId"
  t.integer  "UserID"
  t.datetime "created_at", null: false
  t.datetime "updated_at", null: false
end

如您所见,我无法检测到,添加了“id::integer”。我试图将其更改为:serial,转储我的数据库,重新加载架构(在所有类似的 Stack Overflow 问题中都找到了建议),但没有任何帮助。过去,我曾经建立一个新模型,但这不是一个可扩展的解决方案。任何建议将不胜感激。

我还注意到错误只发生在本地,但从不在生产中(我使用 Heroku)。

如果需要,比较模型:

文章型号:

class Article < ApplicationRecord
  extend FriendlyId
  friendly_id :short_title, use: :slugged
end

代理模型:

class Agent < ApplicationRecord
end

我用:

ruby 2.4.2p198(2017-09-14 修订版 59899)

Rails 5.0.6

psql(9.6.1,服务器 9.6.6)

更新: 为了澄清我在寻找什么 - 我想保留自动生成的 ID,只是防止非空违规错误

【问题讨论】:

  • 完全不相关......但这种情况:t.integer "UserID" 可能会在某些时候让出轨(可能还有开发人员)感到困惑。 rails 假定以大写字母开头的方法是类名,而不是方法/列名... rails 标准将调用它:t.integer "user_id" 代替:) 甚至可能t.references :user(如果你有User 类已经)。 (注意:我当然知道是否有必要出于遗留原因)

标签: ruby-on-rails ruby postgresql ruby-on-rails-5


【解决方案1】:

只需将参数 id: false 添加到您的 create_table 调用中。另外,请注意括号内的内容。

如果有机会,请查看API Dock reference

class CreateAgents < ActiveRecord::Migration[5.0]
  def change
    create_table(:agents, id: false) do |t|
      t.boolean :status
      t.string :stripeId
      t.integer :UserID

      t.timestamps
    end
  end
end

这是一个挑剔的补充,但您可能希望在命名约定中强制执行一些一致性。在列名中使用“Id”或“ID”,但不要混用。它会让您的生活更轻松。

【讨论】:

  • 谢谢,@MarsAtomic 我正在阅读您提供的链接,这听起来像是一个合理的解决方案,但理想情况下,我想保留自动生成的 id(这也发生在我的其他模型上)为什么我很想找到一个不必处理这个问题的通用解决方案——理想情况下)。知道是什么原因造成的吗?
  • @Socha 无法重现。我的架构使用 PG 和 Rails 5.1 清理干净。可能与friendly_id有关?
  • 一定是一些本地数据库问题,我按照这里的步骤stackoverflow.com/a/38666275/8335053 更改本地 postgres 数据库表中的序列,我没有收到错误。我将接受您@MarsAtomic 的回答,因为它是一个很好的解决方案,也可能对其他人有所帮助。
猜你喜欢
  • 2012-03-21
  • 2016-01-23
  • 1970-01-01
  • 1970-01-01
  • 2011-05-14
  • 2012-09-14
  • 2016-06-11
  • 2021-09-25
相关资源
最近更新 更多