Изменение первичного ключа в Rails в строку - PullRequest
26 голосов
/ 15 апреля 2009

Итак, у меня есть две модели, State и Acquisition. State has_many Приобретения. Я чувствовал, что автоинкрементный целочисленный первичный ключ для 51 записи был довольно глупым. Поэтому я изменил модель для государства на PK (State - двухбуквенное сокращение; я нигде не храню фактическое название штата:

class State < ActiveRecord::Base  
  self.primary_key = "state"  
  has_many :acquisition_histories  
end

Проблема в том, что когда я создал свою модель сбора данных, она создала столбец внешнего ключа state_id как целое число. Более конкретно, скрипт / сгенерированная миграция сделали:

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. Проблема заключается в том, что мой метод create в моем классе Acquisition пытается поместить аббревиатуру состояний в поле state_id в таблицах приобретений (и да, в базе данных он называется state_id, хотя в сценарии миграции он говорит: state Метод не терпит неудачу, но он помещает 0 в поле state_id, и записи поступают в эфир.

Ответы [ 9 ]

36 голосов
/ 16 июля 2011

Хотя я согласен, что это может быть больше проблем, чем оно стоит , учитывая дополнительные усилия по работе со значениями по умолчанию в других местах, на тот случай, если вы на самом деле хотите делать то, что вы ' мы спросили:

Миграция создания состояний:

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

32 голосов
/ 04 апреля 2012

если вы окажетесь здесь ... уходите так быстро, как можете, и переходите к: Используя Rails, как я могу установить, чтобы мой первичный ключ не был столбцом целого типа?

6 голосов
/ 15 апреля 2009

Я работаю над проектом, который использует UUID в качестве первичных ключей, и, честно говоря, я не рекомендую его, если вы не уверены, что он вам абсолютно необходим. Существует множество плагинов Rails, которые не будут работать без изменений с базой данных, использующей строки в качестве первичных ключей.

4 голосов
/ 04 января 2018

В Rails 5.1 вы можете указать тип первичного ключа при создании:

create_table :states, id: :string do |t|
# ...
end

С документация :

Символ может использоваться для указания типа сгенерированного столбца первичного ключа.

3 голосов
/ 28 марта 2016

Обратите внимание, что ответ mkirk создает поддельный первичный ключ . Это объясняет, почему 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

* Отказ от ответственности: не следует изменять первичный ключ по умолчанию, если у вас нет веских причин на

2 голосов
/ 15 апреля 2009

Вы хотите следовать соглашениям Rails. Дополнительный первичный ключ не является проблемой в любом случае. Просто используйте это.

1 голос
/ 06 ноября 2010
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
1 голос
/ 15 апреля 2009

У меня был небольшой опыт использования строки в качестве первичных ключей, и это боль в ***. Помните, что по умолчанию, если вы хотите передать объект с шаблоном default: controller /: action /: id, строка: id будет строкой, и это может привести к проблемам с маршрутизацией, если некоторые идентификаторы будут странно отформатированы;)

0 голосов
/ 15 апреля 2009

Рельсы работают лучше всего, когда вы не боретесь со значениями по умолчанию. Какой вред приносит целочисленный первичный ключ в вашей таблице состояний?

Если вы не застряли с устаревшей схемой, которую вы не можете контролировать, я бы посоветовал вам придерживаться Rails по умолчанию - соглашение о конфигурации, верно? в качестве пользовательского интерфейса и бизнес-логики.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...