Search code examples
ruby-on-railsrake

How to use null=>false in a migration file?


I'm changing migration file with create table into add column.

This was the part of the original migration file.

 create_table(:users) do |t|
      t.string :provider, :null => false
      t.string :uid, :null => false, :default => ""

This is something I wrote.

    add_column :users, :provider, :string, :null => false
    add_column :users, :uid, :string, :null => false, :default => ""

This is the error I got while running the migration. How can I correct the migration file?

== 20150527155909 DeviseTokenAuthCreateUsers: migrating =======================
-- add_column(:users, :provider, :string, {:null=>false})
rake aborted!
StandardError: An error has occurred, this and all later migrations canceled:

PG::NotNullViolation: ERROR:  column "provider" contains null values
: ALTER TABLE "users" ADD "provider" character varying NOT NULL/***/db/migrate/20150527155909_devise_token_auth_create_users.rb:3:in `change'
ActiveRecord::StatementInvalid: PG::NotNullViolation: ERROR:  column "provider" contains null values
: ALTER TABLE "users" ADD "provider" character varying NOT NULL
/home/***/db/migrate/20150527155909_devise_token_auth_create_users.rb:3:in `change'
PG::NotNullViolation: ERROR:  column "provider" contains null values
/home/***/db/migrate/20150527155909_devise_token_auth_create_users.rb:3:in `change'
Tasks: TOP => db:migrate
(See full trace by running task with --trace)

Solution

  • You are trying to update the provider and uid columns to not allow null values, and you have written your migration correctly. This error is arising because one or more of them (at least provider) already contains records with null values. You'll have to either drop the records with null providers and/or uids, or update their values (from null to, say, "") before it will work.

    NOTE If you want to easily update these records, and security won't stop you, you could simply open up the rails console and do something like this:

    users = User.all
    users.each do |u|
        u[:provider] = ""
        u[:uid] = ""
        u.save
    end
    

    There are a number of things that could stop this from working, and it may not have your desired result, but it's an option.