Rails: PG::NotNullViolation: ERROR: null value in column "id" violates not-null constraint
The data types
smallserial
,serial
andbigserial
are not true types, but merely a notational convenience for creating unique identifier columns (similar to theAUTO_INCREMENT
property supported by some other databases).
If your column is an integer
, you cannot convert it to serial
, but you can mimic, what PostgreSQL would have done, just like you created your table with a serial:
CREATE SEQUENCE 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;
I had an issue like this when working on a Rails 6 application.
I had a User model that is used to create a student
and an admin
:
class User < ApplicationRecord
belongs_to :role
end
And a Role model:
class Role < ApplicationRecord
end
However, I wanted the admin
and student
roles to be assigned for each admin
and student
respectively when they are created without having a roles field in the forms, so my models were like this:
The Admin model:
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
The Student model:
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
So this was throwing errors whenever I tried creating admins and students:
ActiveRecord::NotNullViolation (PG::NotNullViolation: ERROR: null value in column "role_id" violates not-null constraint)
Here's how I solved it:
The issue was that the role_id
in the users
table was set to null: false
in my migration file. I had to change it to 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
And then also changed the User model, to have the role_id
as optional:
class User < ApplicationRecord
belongs_to :role, optional: true
end
That's all.
I hope this helps