Rails: PG::NotNullViolation: ERROR: null value in column "id" violates not-null constraint

The data types smallserial, serial and bigserial are not true types, but merely a notational convenience for creating unique identifier columns (similar to the AUTO_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