Миграция Rails: добавьте ссылку на таблицу, но другое имя столбца для внешнего ключа, чем Соглашение Rails

у меня есть следующие две модели:

class Store < ActiveRecord::Base
    belongs_to :person
end

class Person < ActiveRecord::Base
    has_one :store
end

вот проблема: я пытаюсь создать миграцию для создания внешнего ключа в таблице people. Однако столбец, ссылающийся на внешний ключ хранилища, не называется store_id как бы rails конвенции, но вместо этого называется foo_bar_store_id.

Если бы я следовал конвенции rails, я бы сделал миграцию следующим образом:

class AddReferencesToPeople < ActiveRecord::Migration
  def change
    add_reference :people, :store, index: true
  end
end

однако это будет не работает, потому что имя столбца не store_id но foo_bar_store_id. Итак, как указать, что имя внешнего ключа просто отличается, но все еще поддерживает индекс: true для поддержания быстрой производительности?

6 ответов


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

add_column :people, :foo_bar_store_id, :integer
add_index :people, :foo_bar_store_id

а затем пусть ваша модель знает внешний ключ так:

class Person < ActiveRecord::Base
  has_one :store, foreign_key: 'foo_bar_store_id'
end

в Rails 4.2 вы также можете настроить модель или миграцию с пользовательским именем внешнего ключа. В вашем примере миграция будет:

class AddReferencesToPeople < ActiveRecord::Migration
  def change
    add_column :people, :foo_bar_store_id, :integer, index: true
    add_foreign_key :people, :stores, column: :foo_bar_store_id
  end
end

здесь интересный пост в блоге на эту тему. здесь полу-загадочный раздел в направляющих рельсов. В блоге определенно помогло мне.

Что касается ассоциаций, явно укажите внешний ключ или имя класса, как это (я думаю, ваши исходные ассоциации были переключены как 'belongs_to' входит в класс с внешним ключом):

class Store < ActiveRecord::Base
  has_one :person, foreign_key: :foo_bar_store_id
end

class Person < ActiveRecord::Base
  belongs_to :foo_bar_store, class_name: 'Store'
end

обратите внимание, что элемент class_name должен быть строкой. Пункт foreign_key может быть строкой или символом. Это по существу позволяет вам получить доступ к отличным ярлыкам ActiveRecord с вашими семантически названными ассоциациями, например:

person = Person.first
person.foo_bar_store
# returns the instance of store equal to person's foo_bar_store_id

подробнее о параметрах ассоциации см. В документации для belongs_to и has_one.


в новых rails вы можете добавить внешний ключ к таблице с другим именем, например:

class AddFooBarStoreToPeople < ActiveRecord::Migration[5.0]
  def change
    add_reference :people, :foo_bar_store, foreign_key: { to_table: :stores }
  end
end

# Migration
change_table :people do |t|
  t.references :foo_bar_store, references: :store #-> foo_bar_store_id
end

# Model
# app/models/person.rb
class Person < ActiveRecord::Base
  has_one :foo_bar_store, class_name: "Store"
end

под обложками add_reference просто делегирует add_column и add_index, поэтому вам просто нужно позаботиться об этом самостоятельно:

add_column :people, :foo_bar_store_id, :integer
add_index :people, :foo_bar_store_id

расширить на ответ schpet, это работает в create_table Rails 5 директива миграции так:

create_table :chapter do |t|
  t.references :novel, foreign_key: {to_table: :books}
  t.timestamps
end