【问题标题】:Rails: PG::NotNullViolation: ERROR: null value in column "id" violates not-null constraintRails:PG :: NotNullViolation:错误:“id”列中的空值违反非空约束
【发布时间】:2022-04-01 18:05:00
【问题描述】:

以下是在 rails 3.2.12 和 pg 9.3 上将记录保存到 postgres 数据库时的错误:

ActiveRecord::StatementInvalid (PG::NotNullViolation: ERROR:  null value in column "id" violates not-null constraint
: INSERT INTO "sw_module_infox_module_infos" ("about_controller", "about_init", "about_log", "about_misc_def", "about_model", "about_onboard_data", "about_subaction", "about_view", "about_workflow", "active", "api_spec", "category_id", "created_at", "last_updated_by_id", "module_desp", "name", "submit_date", "submitted_by_id", "updated_at", "version", "wf_state") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21) RETURNING "id"):
  activerecord (3.2.12) lib/active_record/connection_adapters/postgresql_adapter.rb:1166:in `get_last_result'
  activerecord (3.2.12) lib/active_record/connection_adapters/postgresql_adapter.rb:1166:in `exec_cache'

到目前为止,该表工作正常(在今天出现错误之前保存了大约 50 条记录)。在 pgadmin 中打开 pg 表后。我们发现桌子上的idinteger。我们还发现另一张桌子上的Idserial。似乎 id 应该是 serial 所以它可以自动递增。如果是,那么如何将 id 列从integer 转换为serial?如果不是,那么如何解决这个问题?

【问题讨论】:

  • "serial" 只是 INTEGER 的别名,带有 DEFAULT nextval('some_sequence') ;请参阅用户手册。
  • 表是使用 rails rake db:migrate 创建的。 33 个表中约有 8 个具有整数类型。其余的是串行的。有些表也缺少索引。不知道是什么导致了postgres的问题。 sqlite创建的同一张表完全没有这个问题。

标签: ruby-on-rails postgresql


【解决方案1】:

数据类型smallserial, serial and bigserial 不是真正的类型,而只是一种用于创建唯一标识符列的符号方便(类似于某些其他数据库支持的AUTO_INCREMENT 属性)。

如果您的列是integer,您不能它转换为serial,但您可以模仿PostgreSQL 会做的事情,就像您使用序列创建表一样:

创建序列 tablename_colname_seq;
ALTER TABLE tablename ALTER COLUMN colname SET DEFAULT nextval('tablename_colname_seq'::regclass);
ALTER SEQUENCE tablename_colname_seq OWNED BY tablename.colname;

【讨论】:

  • 什么可能导致问题? sqlite 已经使用了相同的迁移,并且从来没有这样的问题。 33 个表中约有 8 个的 id 为整数(不是序列)。其中一些也缺少索引。它开始困扰我们,因为我们不知道为什么它会发生在 postgres 上。我们认为 postgres 比 sqlite 更强大。
  • @user938363 再次,serial 不是真正的类型。您的所有列都是integer(在 PgAdmin 中,您可以在其 Properties > Data Type 上检查它)。您的列之间的区别只是默认值及其序列的存在。 -- 这些表在 ruby​​ 中的定义肯定有一些区别,所以 rails 决定不像连续剧那样构建它们,但这应该是一个不同的问题(主要是 rails / rake 相关的)
  • @@pozs,我们需要将序列设置为下一个可用的 id 吗?或者上面的 3 个命令已经做到了。
  • @user938363 这只会修复结构,如果您的值也有问题,请参阅stackoverflow.com/questions/244243/…
【解决方案2】:

我在使用 Rails 6 应用程序时遇到了这样的问题。

我有一个 User 模型,用于创建 studentadmin

class User < ApplicationRecord
  belongs_to :role
end

还有一个角色模型:

class Role < ApplicationRecord
end

但是,我希望在创建 adminstudent 时分别为每个 adminstudent 分配角色在表单中没有角色字段,所以我的模型是这样的:

管理员模型:

class Admin < ApplicationRecord
  before_save :set_admin_role

  belongs_to :user

  private

  def set_admin_role
    # set role_id to '1' except if role_id is not empty
    user.role_id = '1' if user.role_id.nil?
  end
end

学生模型:

class Student < ApplicationRecord
  before_save :set_student_role

  belongs_to :user

  private

  def set_student_role
    # set role_id to '2' except if role_id is not empty
    user.role_id = '2' if user.role_id.nil?
  end
end

所以每当我尝试创建管理员和学生时,这都会引发错误:

ActiveRecord::NotNullViolation (PG::NotNullViolation: ERROR:  null value in column "role_id" violates not-null constraint)

我是这样解决的

问题是users 表中的role_id 在我的迁移文件中设置为null: false。我不得不把它改成null: true

class CreateUsers < ActiveRecord::Migration[6.0]
  def change
    create_table :users do |t|
      t.string :email
      t.string :password_digest
      t.references :role, null: true, foreign_key: true

      t.timestamps
    end
  end
end

然后还更改了 User 模型,将role_id 作为可选:

class User < ApplicationRecord
  belongs_to :role, optional: true
end

就是这样。

我希望这会有所帮助

【讨论】:

  • 这是完美的文档,正是我想要的!感谢您为我节省了时间!
【解决方案3】:

我有一个非常相似的问题。

我会告诉你哪里出了问题,也许有人会发现我的经验很有用

我有ERROR: null value in column "created_at" violates not-null constraint

问题是我有一个在before_createbefore_save 中运行的方法,而这个方法试图通过小更新来保存。所以它尝试保存了几次。

我的建议是检查您的代码在 before_save 中的作用 和before_create

【讨论】:

    【解决方案4】:

    只需将optional: true 添加到我们必须映射的模型中

    示例:

    用户:

    class User < ApplicationRecord
    
      has_many :tasks
    end
    

    任务:

    class Task < ApplicationRecord
    
      belongs_to :user, optional: true
    
    end
    
    set ----->  null: true , in ur DB/migration/
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-08
      • 2020-03-15
      • 2021-03-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多