2009-06-30 3 views
37

Как изменить тип (по умолчанию) для идентификаторов ActiveRecord? int не достаточно длинный, я бы предпочел бы долго. Я был удивлен, что нет: долго для миграции - используется ли какой-нибудь десятичный знак?Как использовать длинный идентификатор в приложениях Rails?

ответ

48

Кредиты на 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 
  • Смотрите опцию :id => false который отключает автоматическое создание поля идентификатора
  • t.integer :id, :limit => 8 линия будет производить 64 бит целое поле
+0

Спасибо, отлично! Работает в Rails 2.3.11, также. – nessur

+10

К сожалению, это не создает столбец id как первичный ключ и т. Д. – gravitystorm

+1

True. Я сделал это с сырым SQL. Я прочитал эту грусть, и я не нашел возможности сделать это разумно (3.0.7). Это позор. Но эй! 3.1.0 на какое-то время! Удачи! – Notinlist

6

Согласно документации API Rails, возможные варианты типа:

:string 
:text 
:integer 
:float 
:decimal 
:datetime 
:timestamp 
:time 
:date 
:binary 
:boolean 

Вы можете использовать: десятичные, или вы можете выполнить команду непосредственно, если вам нужно:

class MyMigration 
    def self.up 
    execute "ALTER TABLE my_table ADD id LONG" 
    end 
end 

Как указывалось wappos, вы можете использовать вспомогательные параметры, такие как: limit, чтобы сообщить ActiveRecord, насколько велика ваша колонка. Таким образом, вы должны использовать столбец: int с большим лимитом.

+0

«Как wappos отметил, вы можете использовать дополнительные опции, как:. Предел сказать ActiveRecord, насколько велика вы хотите, чтобы столбец быть Таким образом, вы бы использовать : int column с большим лимитом ". Я не думаю, что это сработает, если то, что он хочет, будет больше целого. Установка большего ограничения не изменит максимальный размер. –

+0

: primary_key не имеет опции: limit, поэтому это не работает для столбца первичного ключа. –

+2

Я просто просмотрел его в документах Rails, и если вы используете: limit => 8 на целочисленном столбце, вы получите bigint. Я этого не понимал. –

7

Трудно установить первичный ключ с миграциями, потому что Rails ставит его автоматически.

Вы можете изменить любой столбец позже, как это:

change_column :foobars, :something_id, 'bigint'

Вы можете указать несырьевых идентификаторы, как пользовательские типы в вашей первоначальной миграции, как это:

create_table :tweets do |t| 
    t.column :twitter_id, 'bigint' 
    t.column :twitter_in_reply_to_status_id, 'bigint' 
end 

Где у меня есть " bigint "вы можете поместить любой текст, который ваша база данных будет использовать для типа столбца базы данных, который вы хотите использовать (например,« unsigned long »).

Если вам нужно, чтобы столбец id был большим, самым простым способом было бы создать таблицу, а затем изменить столбец в той же миграции с помощью change_column.

С PostgreSQL и SQLite изменения схемы являются атомарными, поэтому это не приведет к тому, что ваша база данных окажется в странном состоянии, если миграция завершится с ошибкой. С MySQL вам нужно быть более осторожным.

+0

Спасибо - кажется, что для «нормального» столбца с использованием limit => 8 будет трюк, но для primary_key это не работает. Для MySQL я теперь использовал пользовательский SQL с execute. Предпочитал бы change_column, но не имел бы той же проблемы, что и первоначальное создание, а именно: limit => 8 не поддерживался бы для столбцов первичного ключа? –

+1

Нет, вы можете использовать change_column с первичным ключом, например: change_column: foobars,: id, "bigint". Таким образом, вы создадите таблицу, а затем сразу же измените столбец идентификаторов, чтобы быть bigint. Я все еще не думаю, что использование: ограничение с столбцом int будет работать (с MySQL в любом случае), потому что максимальный размер int равен 2 ** 31-1 независимо от того, что. –

+1

ОК, я просто просмотрел его в документах Rails, и если вы сделаете t.column: foobar,: int,: limit => 8, вы получите bigint. –

43

Для установки столбца первичного ключа по умолчанию, файлы миграции не являются местом для взаимодействия.

Вместо этого, просто придерживаться этого в нижней части вашего config/environment.rb

ActiveRecord::ConnectionAdapters::MysqlAdapter::NATIVE_DATABASE_TYPES[:primary_key] = "BIGINT UNSIGNED DEFAULT NULL auto_increment PRIMARY KEY" 

И все ваши таблицы должны быть созданы с намеченным колонного типа для id:

+--------------+---------------------+------+-----+---------+----------------+ 
| Field  | Type    | Null | Key | Default | Extra   | 
+--------------+---------------------+------+-----+---------+----------------+ 
| id   | bigint(20) unsigned | NO | PRI | NULL | auto_increment | 

После того, как вы сделали то, что вы намеревались сделать ... следующий вопрос, вероятно, «Как мне сделать столбцы внешнего ключа одним и тем же типом столбца?» так как нет смысла иметь первичный ключ people.id как bigint(20) unsigned, а person_id - int(11) или что-нибудь еще?

Для этих столбцов вы можете обратиться к другим предложениям, например.

t.column :author_id, 'BIGINT UNSIGNED' 
t.integer :author_id, :limit => 8 

UPDATE: @Notinlist, чтобы использовать произвольный столбец для первичного ключа на произвольных таблиц вы должны сделать create_table-change_column танец:

create_table(:users) do |t| 
    # column definitions here.. 
end 
change_column :users, :id, :float # or some other column type 

например если бы я хотел guid вместо автоинкрементных чисел,

create_table(:users, :primary_key => 'guid') do |t| 
    # column definitions here.. 
end 
change_column :users, :guid, :string, :limit => 36 
+1

Это полезный подход, но есть ли способ сделать эту независимую от базы данных или это просто цена, которую вы платите за эту потребность? – brokenbeatnik

+0

, вероятно, последний. – choonkeat

+1

Что делать, если я не хочу использовать 'bigint' для всех моих таблиц, только для некоторых? – Notinlist

2

Rails 3, MySQL:

t.column :foobar, :int, :limit => 8 

Не дает мне BIGINT, лишь Int. Однако

t.column :twitter_id, 'bigint' 

работает нормально. (Хотя это не привязывать меня к MySQL.)

+0

'bigint' как тип столбца также должен работать на PostgreSQL. Я использовал его на днях для столбца int размером 8. –

+0

Прохладный! MySQL и PostgreSQL - единственные, которые кажутся мне важными. На самом деле, теперь они принадлежат той же организации, которую я слышал. – Duke

+1

MySQL теперь принадлежит Oracle, но это не относится к PostgreSQL, что, вероятно, означает, что оно будет процветать больше :) – m33lky

2

Заимствование из других решений, скорректированное на то, что сработало для меня в последнее время.

Добавить в файл в config/initializers. Он объявляет новый тип столбца (адаптированный из предложения chookeat).

ActiveRecord::ConnectionAdapters::Mysql2Adapter::NATIVE_DATABASE_TYPES[:long_primary_key] = "BIGINT(20) DEFAULT NULL auto_increment PRIMARY KEY"

Миграция, которые используют длинный идентификатор, как таковые:

create_table :notification_logs, :id => false do |t| 

     t.column :id, :long_primary_key 
     # ... 
    end 
5

Если кому-то нужно, чтобы это работать с PostgreSQL, создать инициализатору вроде этого:

# config/initializers/bigint_primary_keys.rb 
ActiveRecord::Base.establish_connection 
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::NATIVE_DATABASE_TYPES[:primary_key] = 'bigserial primary key' 

Из-за ленивая загрузка в Rails 3.2 (и, возможно, даже более ранние версии), ActiveRecord::ConnectionAdapters::PostgreSQLAdapter не потребуется, пока вы не установите соединение с базой данных.

+0

Вам не нужно устанавливать соединение для выполнения требования, просто требуется соответствующий адаптер, например. для 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'. –

0

Я написал драгоценный камень под названием activerecord-native_db_types_override, который позволяет вам изменять типы данных, которые будут использоваться в ваших миграциях.

В вашем Gemfile добавить:

gem 'activerecord-native_db_types_override' 

затем в конфигурации/environment.rb, чтобы использовать длинные идентификаторы в Postgres, добавьте:

NativeDbTypesOverride.configure({ 
    postgres: { 
    primary_key: { name: "bigserial primary key"} 
    } 
}) 

Смотрите его README для уточненного Информация.

-1

Correction как изменить по умолчанию тип в primary key колонки:

Вместо:

ActiveRecord::ConnectionAdapters::MysqlAdapter::NATIVE_DATABASE_TYPES[:primary_key] = "BIGINT UNSIGNED DEFAULT NULL auto_increment PRIMARY KEY" 

вы должны сделать:

ActiveRecord::ConnectionAdapters::MysqlAdapter::NATIVE_DATABASE_TYPES[:primary_key] = "BIGINT(8) UNSIGNED DEFAULT NULL auto_increment PRIMARY KEY" 

, иначе вы не сможете добавить foreign key ограничений в слое базы данных.

+0

Не могли бы вы предоставить более подробную информацию о различии между 'BIGINT (** 8 **)' и 'BIGINT' и как это повлияет на создание внешнего ключа в MySQL? (Я пробовал поиск в Google и искал документацию по MySQL, но специальные символы устраивают поиск.) – MothOnMars

+1

Я подозреваю, что OP просто помещал эти звездочки для акцента. Я отредактировал, чтобы удалить их. Он также ошибается, BTW - значения точности для чисел в MySQL влияют только на их ширину отображения, и в этом случае нет необходимости. – SFEley

4

В rails4 вы можете это сделать.

Ниже приведен пример создания Dummy модели в 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 

Что это было:

  • Он использует serial8 в виде id, который является 64-битным целым числом и определяет его как primary key.
  • Он использует timestamptz как тип даты, который содержит информацию о часовом поясе, это важно для приложения, использующего несколько часовых поясов.
0

Вы можете сделать это следующим образом:

class CreateUsers < ActiveRecord::Migration[5.0] 
    def change 
    create_table :users, id: :bigserial do |t| 
     t.string :name 
    end 
    end 
end 
Смежные вопросы