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 structure of data, for example:
things
------
id bigint primary_key
name char(32)
The approach I'm currently trying to push:
create_table :things, :id => false do |t| # That prevents the creation of (id int) PK
t.integer :id, :limit => 8 # That makes t开发者_JS百科he column type bigint
t.string :name, :limit => 32
t.primary_key :id # This is perfectly ignored :-(
end
The column type will be correct, but the primary key option will not be present with sqlite3 and I suspect that this is the case for MySQL too.
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"
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.
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
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
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
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
精彩评论