Подтвердить что ты не робот

Изменение первичного ключа в 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, и записи переходят в эфир.

4b9b3361

Ответ 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

Ответ 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