开发者

rails3 bigint primary key

开发者 https://www.devze.com 2023-03-03 06:01 出处:网络
I would like to create a bigint (or string or whatever that is not int) typed primary key field under Rails 3.

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
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号