How can I change the (default) type for ActiveRecord's IDs? int is not long enough, I would prefer long. I was surprised that there is no :long for the migrations - does one just use some decimal?
-
NOTE, things change dramatically in Rails 5, including defaulting to `bigint`, so take all of the below answers with a grain of salt if you're on Rails 5+. – Joshua Pinter Dec 29 '20 at 21:47
11 Answers
Credits to http://moeffju.net/blog/using-bigint-columns-in-rails-migrations
class CreateDemo < ActiveRecord::Migration
def self.up
create_table :demo, :id => false do |t|
t.integer :id, :limit => 8
end
end
end
- See the option
:id => false
which disables the automatic creation of the id field - The
t.integer :id, :limit => 8
line will produce a 64 bit integer field

- 16,144
- 10
- 57
- 99
-
11Unfortunately this doesn't create the id column as primary key etc. – gravitystorm Jan 16 '12 at 13:42
-
1True. I did that with raw SQL. I've read the soruce, and I did not find any option to do that intelligently (3.0.7) . That's a shame. But hey! 3.1.0 is out for a while! Good luck! – Notinlist Jan 16 '12 at 14:12
-
I found this because I was looking for *any* field to be set to bigint in postgres. The :id information is a bonus! – gak Dec 11 '12 at 20:59
-
@EricWang It was a long time ago, I don't do Ruby on Rails (or even) nowdays. But this one I used regularly and I don't remember having any regression in relation to a "classic" identifier. – Notinlist Oct 19 '15 at 09:11
-
@Notinlist The question is about `long id`, not just `long`, thus the column is better be declared as primary key. – Eric Oct 19 '15 at 11:35
To set the default primary key column type, the migration files are not the place to mess with.
Instead, just stick this at the bottom of your config/environment.rb
ActiveRecord::ConnectionAdapters::MysqlAdapter::NATIVE_DATABASE_TYPES[:primary_key] = "BIGINT UNSIGNED DEFAULT NULL auto_increment PRIMARY KEY"
And all your tables should be created with the intended column type for id
:
+--------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+---------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
After you've done what you've set out to do... the next question is probably "How do I make my foreign key columns the same column type?" since it does not make sense to have primary key people.id
as bigint(20) unsigned
, and person_id
be int(11)
or anything else?
For those columns, you can refer to the other suggestions, e.g.
t.column :author_id, 'BIGINT UNSIGNED'
t.integer :author_id, :limit => 8
UPDATE: @Notinlist, to use arbitrary column for primary key on arbitrary tables you need to do the create_table-change_column
dance:
create_table(:users) do |t|
# column definitions here..
end
change_column :users, :id, :float # or some other column type
e.g. if I wanted guid
instead of auto-increment integers,
create_table(:users, :primary_key => 'guid') do |t|
# column definitions here..
end
change_column :users, :guid, :string, :limit => 36

- 5,557
- 2
- 26
- 19
-
1This is a useful approach, but is there any way to make this database-independent or is that just the price one pays for this need? – brokenbeatnik Feb 02 '11 at 01:21
-
1What if I don't want to use `bigint` for all my tables, just for some? – Notinlist May 04 '11 at 08:32
-
then 1) you should leave the config/environment.rb alone. 2) issue a "change_column" after your "create_table" to use bigint (see the last snippet) – choonkeat Jun 28 '11 at 07:57
-
1Looks like `:primary_key => 'guid'` then changing to string won't work. If I'm understanding correctly, a reference to `primary_key` in a migration, by definition, creates an auto-incrementing field, so it wouldn't work on strings. See Rudd Zwolinski's answer [here](http://stackoverflow.com/questions/1200568/using-rails-how-can-i-set-my-primary-key-to-not-be-an-integer-typed-column). – Mark Berry Oct 11 '11 at 00:52
-
@choonkeat, you're right, that works. Looks like with sqlite3, `change_column` completely drops and re-adds the table (see `development.log`). So `"guid" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL` becomes simply `"guid" varchar(36)`. It is no longer a primary key, NULL is allowed, and it is not indexed. In PostgreSQL, `:guid` is changed with ALTER COLUMN` so it's still the primary key and still auto-increments (1, 2, 3). – Mark Berry Oct 23 '11 at 21:49
-
2I would **very** much recommend against create-then-change, at least in Rails 2.3.x. If you check your db/schema.rb file after running this migration, you'll notice it has no mention of your changes, so anyone creating your DB from the schema (like tests) will not have the same structure. – Groxx Jun 19 '12 at 18:40
-
1For mysql2 adapter add: `if ActiveRecord::ConnectionAdapters.local_constant_names.include?("Mysql2Adapter") ActiveRecord::ConnectionAdapters::Mysql2Adapter::NATIVE_DATABASE_TYPES[:primary_key] = "BIGINT UNSIGNED DEFAULT NULL auto_increment PRIMARY KEY" end ` – mustafaturan Sep 14 '12 at 21:57
This is hard to set for the primary key with migrations because Rails puts it in automatically.
You can change any column later like this:
change_column :foobars, :something_id, 'bigint'
You can specify non-primary IDs as custom types in your initial migration like this:
create_table :tweets do |t|
t.column :twitter_id, 'bigint'
t.column :twitter_in_reply_to_status_id, 'bigint'
end
Where I have "bigint" you can put any text that your database would use for the database column type you want to use (e.g., "unsigned long").
If you need your id column to be a bigint, the easiest way to do it would be to create the table, then change the column in the same migration with change_column.
With PostgreSQL and SQLite, schema changes are atomic so this won't leave your database in a weird state if the migration fails. With MySQL you need to be more careful.

- 31,028
- 18
- 69
- 91
-
Thanks - it seems for a "normal" column using limit => 8 would do the trick, but for the primary_key this does not work. For MySQL I have now used custom SQL with execute. Would prefer change_column, but wouldn't that have the same problem as initial creation, namely that :limit => 8 would not be supported for primary key columns? – Björn Jul 01 '09 at 16:08
-
1No, you can use change_column with the primary key, like this: change_column :foobars, :id, "bigint". So you'd create the table and then immediately change the ID column to be a bigint. I still don't think using :limit with an int column is going to work (with MySQL anyway) because int's max size is 2**31-1 no matter what. – Luke Francl Jul 01 '09 at 23:45
-
1OK, I just looked it up in the Rails docs and if you do t.column :foobar, :int, :limit => 8 you will get a bigint. – Luke Francl Jul 02 '09 at 07:29
According to the Rails API documentation, the possible options for type are:
:string
:text
:integer
:float
:decimal
:datetime
:timestamp
:time
:date
:binary
:boolean
You can use :decimal, or you can execute a command directly if you need to:
class MyMigration
def self.up
execute "ALTER TABLE my_table ADD id LONG"
end
end
As wappos pointed out, you can use auxiliary options like :limit to tell ActiveRecord how large you want the column to be. So you would use the :int column with a larger :limit.

- 28,535
- 12
- 89
- 91
-
"As wappos pointed out, you can use auxiliary options like :limit to tell ActiveRecord how large you want the column to be. So you would use the :int column with a larger :limit." I don't think that will work if what he wants is larger than integer will hold. Setting a larger limit won't change the maximum size. – Luke Francl Jul 01 '09 at 06:01
-
in fact :primary_key does not have the :limit option, so this does not work for the primary key column. – Björn Jul 01 '09 at 16:05
-
2I just looked it up in the Rails docs and if use :limit => 8 on an integer column you will get a bigint. I did not realize that. – Luke Francl Jul 02 '09 at 07:30
If anyone needs this to work with PostgreSQL, create an initializer like this:
# config/initializers/bigint_primary_keys.rb
ActiveRecord::Base.establish_connection
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::NATIVE_DATABASE_TYPES[:primary_key] = 'bigserial primary key'
Because of lazy loading in Rails 3.2 (and maybe even earlier versions), ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
won't be required until you establish the database connection.

- 14,735
- 3
- 56
- 71
-
You don't need to establish a connection to do the require, just require the appropriate adapter, e.g. for pg: require 'active_record/connection_adapters/postgresql_adapter', mysql: require 'active_record/connection_adapters/abstract_mysql_adapter', sqlite: require 'active_record/connection_adapters/sqlite3_adapter', oracle: require 'active_record/connection_adapters/oracle_enhanced_adapter'. – Gary S. Weaver Jan 11 '13 at 20:17
In rails4
, you can do it.
Following is an example to create a Dummy
model in rails4
& postgres
,
xxx_migrate_dummies.rb:
class CreateDummies < ActiveRecord::Migration
def change
create_table :dummies, :id => false do |t|
t.column :id, :serial8, primary_key: true
t.string :name, :limit => 50, null: false
t.integer :size, null: false
t.column :create_date, :timestamptz, null: false
end
end
end
What it did:
- It use
serial8
as id type, which is 64 bit integer, and define it asprimary key
. - It use
timestamptz
as datetime type, which contain the timezone info, this is important for a application that go across multiple timezones.

- 22,183
- 20
- 145
- 196
Borrowing from other solutions, adjusted for what worked for me recently.
Add to a file in config/initializers
. It declares a new column type (adapted from chookeat's suggestion).
ActiveRecord::ConnectionAdapters::Mysql2Adapter::NATIVE_DATABASE_TYPES[:long_primary_key] = "BIGINT(20) DEFAULT NULL auto_increment PRIMARY KEY"
Migrations that use a long id are as such:
create_table :notification_logs, :id => false do |t|
t.column :id, :long_primary_key
# ...
end

- 23,606
- 10
- 74
- 129
Rails 3, MySQL:
t.column :foobar, :int, :limit => 8
Does not give me a bigint, only an int. However,
t.column :twitter_id, 'bigint'
works fine. (Although it does tie me to MySQL.)

- 7,070
- 3
- 38
- 28
-
'bigint' as a column type should also work on PostgreSQL. I used it the other day for an int column of size 8. – Bo Jeanes Jan 27 '11 at 07:27
-
Cool! MySQL and PostgreSQL are the only ones that seem at all relevant to me. Actually, they're now owned by the same org I hear.. – Duke Feb 17 '11 at 05:48
-
1MySQL is now owned by Oracle, but this is not the case for PostgreSQL, which probably means that it will thrive more :) – m33lky Dec 23 '11 at 00:22
I wrote a gem called activerecord-native_db_types_override that lets you alter the datatypes that will be used in your migrations.
In your Gemfile, add:
gem 'activerecord-native_db_types_override'
then in config/environment.rb, to use long ids in postgres, add:
NativeDbTypesOverride.configure({
postgres: {
primary_key: { name: "bigserial primary key"}
}
})
See its README for up-to-date info.

- 7,966
- 4
- 37
- 61
You can do it like this:
class CreateUsers < ActiveRecord::Migration[5.0]
def change
create_table :users, id: :bigserial do |t|
t.string :name
end
end
end

- 1,049
- 16
- 32
Correction to how to change the default primary key
column type:
Instead of:
ActiveRecord::ConnectionAdapters::MysqlAdapter::NATIVE_DATABASE_TYPES[:primary_key] = "BIGINT UNSIGNED DEFAULT NULL auto_increment PRIMARY KEY"
you should do:
ActiveRecord::ConnectionAdapters::MysqlAdapter::NATIVE_DATABASE_TYPES[:primary_key] = "BIGINT(8) UNSIGNED DEFAULT NULL auto_increment PRIMARY KEY"
or else you won't be able to add foreign key
restrictions in the database layer.
-
Could you provide more detail in the difference between `BIGINT(**8**)` and `BIGINT`, and how it affects foreign key creation in MySQL? (I tried googling and searching the MySQL documentation, but the special characters are borking the search.) – MothOnMars Feb 25 '13 at 20:26
-
2I suspect the OP was just putting those asterisks in for emphasis. I edited to remove them. He's also wrong, BTW -- precision values for numbers in MySQL only affect their display width, and there's no need for them in this case. – SFEley Mar 14 '13 at 19:49
-
Note, as of Rails ~5, overriding the `primary_key` like this no longer works. It is simply ignored. The good news is that as of Rails ~5, the default column type for primary keys is `bigint`. However, it is not `unsigned`. If you want `unsigned` to be the default, please look at this Github issue and show your support: https://github.com/rails/rails/issues/40967 – Joshua Pinter Dec 29 '20 at 21:46