Изменение первичного ключа в Rails будет строкой
Итак, у меня есть две модели: State и Acquisition. Состояние has_many Acquisitions. Я чувствовал себя как автоинкрементный целочисленный первичный ключ для 51 записи, был довольно глупым. Таким образом, я изменил модель для государства как PK (состояние, являющееся аббревиатурой двух букв, я не сохраняю фактическое имя состояния в любом месте:
class State < ActiveRecord::Base
self.primary_key = "state"
has_many :acquisition_histories
end
Проблема заключается в том, что когда я создал свою модель Acquisition, она создала столбец внешнего ключа state_id как целое число. Более конкретно, миграция script/сгенерирована:
class CreateAcquisitions < ActiveRecord::Migration
def self.up
create_table :acquisitions do |t|
t.date :date
t.string :category
t.text :notes
t.references :state
t.timestamps
end
end
end
Я предполагаю, что тип данных t.references устанавливает его в int. Проблема заключается в том, что мой метод создания в моем классе Acquisition пытается поместить аббревиатуру состояния в поле state_id при приобретении таблицы (и да, он называется state_id в базе данных, хотя он говорит: состояние в миграции script). Метод не прерывается, но он помещает 0 в поле state_id, и записи переходят в эфир.
Ответы
Ответ 1
Rails лучше всего работает, когда вы не сражаетесь с настройками по умолчанию. Какой вред он делает, чтобы иметь цельный первичный ключ в таблице состояний?
Если вы не застряли в устаревшей схеме, в которой у вас нет контроля, я бы посоветовал вам придерживаться соглашения Rails по умолчанию и соглашения о конфигурации, правильно? — и сосредоточиться на важных частях вашего приложения, таких как как пользовательский интерфейс и бизнес-логику.
Ответ 2
Хотя я согласен, что это может быть больше проблем, чем стоит, учитывая дополнительные усилия по работе с дефолтами в другом месте, на всякий случай, если вы действительно хотите сделать то, что вы спросили:
Создание миграции состояний:
class CreateStatesTable < ActiveRecord::Migration
def change
create_table :states, id: false do |t|
t.string :state, limit: 2
t.string :name
t.index :state, unique: true
end
end
end
Модель состояний :
class State < ActiveRecord::Base
self.primary_key = :state
end
Обратите внимание, что перед Rails 3.2 это было set_primary_key = :state
вместо self.primary_key=
: http://guides.rubyonrails.org/3_2_release_notes.html#active-record-deprecations
Ответ 3
если вы окажетесь здесь... оставьте как можно быстрее и идите:
Используя Rails, как я могу установить свой первичный ключ, чтобы он не был столбцом с целым типом?
Ответ 4
Я работаю над проектом, который использует UUID в качестве первичных ключей, и, честно говоря, я не рекомендую его, если вы не уверены, что вам это абсолютно необходимо. Там есть тонна плагинов Rails, которые не будут работать без изменений с базой данных, которая использует строки в качестве первичных ключей.
Ответ 5
Обратите внимание, что ответ mkirk создает первичный ключ faux. Это объясняет, почему ActiveRecord необходимо сообщить, что такое первичный ключ. Проверка таблицы показывает
Table "public.acquisitions"
Column | Type | Modifiers
--------+----------------------+-----------
state | character varying(2) |
name | character varying |
Indexes:
"index_acquisitions_on_state" UNIQUE, btree (state)
На практике это работает так, как ожидалось, поэтому ничего плохого нет, но это может быть лучше.
Мы можем сохранить столбец id
и изменить его тип на string
*. Миграция выглядит как
class CreateAcquisitionsTable < ActiveRecord::Migration
def change
create_table :acquisitions do |t|
t.string :name
end
change_column :acquisitions, :id, :string, limit: 2
end
end
Проверка таблицы показывает, что у вас есть реальный первичный ключ со всеми преимуществами, такими как уникальное ограничение ключа (не требуется уникальный индекс), а не ограничение на нуль и автоматически увеличивающий ключ.
Table "public.acquisitions"
Column | Type | Modifiers
--------+----------------------+---------------------------------------------------
id | character varying(2) | not null default nextval('acquisitions_id_seq'::regclass)
name | character varying |
Indexes:
"acquisitions_pkey" PRIMARY KEY, btree (id)
И вам не нужно явно указывать ActiveRecord, что является основным.
Вы хотите рассмотреть возможность установки идентификатора по умолчанию, если он не указан.
class MyModel < ActiveRecord::Base
before_create do
self.id = SecureRandom.uuid unless self.id
end
end
* Отказ от ответственности: вы не должны изменять первичный ключ по умолчанию, если у вас нет веских оснований для
Ответ 6
В Rails 5.1 вы можете указать тип первичного ключа при создании:
create_table :states, id: :string do |t|
# ...
end
Из документация:
Символ может использоваться для указания типа сгенерированного столбца первичного ключа.
Ответ 7
Вы хотите следовать соглашениям Rails. Дополнительный первичный ключ никоим образом не является проблемой. Просто используйте его.
Ответ 8
У меня был немного опыта с строкой, используемой в качестве первичных ключей, и это боль в ***. Помните, что по умолчанию, если вы хотите передать объект с шаблоном по умолчанию: controller/: action/: id, идентификатор: будет строкой, и это, вероятно, приведет к ошибкам маршрутизации, если некоторые идентификаторы будут отформатированы в форме;)
Ответ 9
class CreateAcquisitions < ActiveRecord::Migration
def self.up
create_table :acquisitions, :id => false do |t|
t.date :date
t.string :category
t.text :notes
t.references :state
t.timestamps
end
end
end