I would like to create a bigint
(or string
or whatever that is not int
) typed primary key field under Rails 3.
I have a given
skalogirou's answer is good but the change will not be reflected in schema.rb. So the tasks like db:schema:load
and db:test:clone
will not create identical DB structure.
The required workaround is to enhance db:schema:load
and db:test:clone rake tasks as described here:
http://www.lshift.net/blog/2013/09/30/changing-the-primary-key-type-in-ruby-on-rails-models/
This is what I used based on that workaround:
namespace :my_app do
namespace :db do
task :after_schema_load_and_db_test_clone => :environment do
puts 'Changing primary key for :my_table'
query = 'ALTER TABLE <my_table> CHANGE id id bigint DEFAULT NULL auto_increment'
ActiveRecord::Base.connection.execute(query)
end
end
Rake::Task['db:schema:load'].enhance do
::Rake::Task['my_app:db:after_schema_load_and_db_test_clone'].invoke
end
Rake::Task['db:test:clone'].enhance do
::Rake::Task['my_app:db:after_schema_load_and_db_test_clone'].invoke
end
For those of you who came here (like I did) in an effort to figure out how to make a custom id
column that uses bigint
instead of int
, what I didn't realize is that for Rails 5.1 and above, bigint
is the default type for id
https://github.com/rails/rails/pull/26266
If you want to convert all tables in Postgres you will need to run this code
class ConvertIntToBigint < ActiveRecord::Migration[5.1]
def up
query = <<-SQL
SELECT tablename AS "tablename"
FROM pg_tables
WHERE schemaname = 'public';
SQL
connection.execute(query).each do |element|
if column_exists?(element['tablename'], :id, :integer)
change_table(element['tablename']) {|t| t.change :id, :bigint }
end
end
end
def down
end
end
Had that myself not long ago and found the answer here: Using Rails, how can I set my primary key to not be an integer-typed column?
You need to set primary_key: false and then use a custom statement before you execute the migration.
EDIT 1: You need to check your database docs for the exact query to perform. It is executed as a regular SQL statement and needs to be database specific. The example in the question I referred to is for Postgre SQL. If you are on MySQL you might have to change that.
I had the same problem. I think the easiest way for a table
accounts
id bigint primary key
name char
is
create_table :accounts do |t|
t.string :name
end
change_column :accounts, :id , "bigint NOT NULL AUTO_INCREMENT"
For MySQL you can use "SERIAL" which is alias for "BIGINT UNSIGNED NOT NULL AUTO_INCREMENT"
class ChangeUserIdToBigint < ActiveRecord::Migration
def change
change_column :users, :id, 'SERIAL'
end
end