2013-04-27 4 views
28

Я совершенно новичок в рельсах и стараюсь работать с ним всю ночь без везения.Добавление внешнего ключа к модели рельсов

Я создал 3 модели: users, businesses и business_hours. Я также добавил ассоциации (business_hours belongs_to businesses which belongs_to users) и (user has_one business which has_many business_hours).

Чтение через документы в Интернете Кажется, мне теперь нужно создать внешние ключи для этих отношений в моих таблицах БД. Как это сделать, используя миграцию Rails ActiveRecord? Я использую PostgreSQL как свою БД.

ответ

23

Прежде всего, когда вы используете метод belongs_to, не используйте s в конце слова: business_hours belongs_to business which belongs_to user.

Теперь создайте миграцию:

rails generate migration migration_name 

И в миграции добавить столбцы:

class MigrationName < ActiveRecord::Migration 
    def change 
    add_foreign_key :business_hours, :businesses 
    add_foreign_key :businesses, :users 
    end 
end 

rake db:migrate Выполнить. Вот и все.

+0

Должен ли я добавить столбец business_id предприятиям и столбец user_id для пользователей, если они не имеют их? – 2013-04-27 21:55:19

+0

Хорошо. Когда я запускаю db: migrate, я получаю эту ошибку: PG :: Ошибка: ERROR: отношение «бизнес» не существует – 2013-04-27 22:06:38

+0

Извините, я нашел свою ошибку в методе def def. Спасибо за вашу помощь! – 2013-04-27 22:09:45

5

Я не пробовал это с PostgreSQL, но по крайней мере с MySQL Rails НЕ создают внешние ключи, я имею в виду не реальные внешние ключи уровня db. Все, что они создают, - это целое число, указанное по соглашению. Это означает, что из коробки вы не получаете индекс этого фальшивого внешнего ключа (для более быстрого поиска), а также нет проверки ссылочной целостности уровня db. Для того, чтобы получить, что вам нужно сделать что-то вроде:

ALTER TABLE your_table ADD CONSTRAINT fk_whatever_you_want_to_name_it FOREIGN KEY (foreign_key_name) REFERENCES another_table(its_primary_key) 

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

+0

Это новость для меня. Я хочу, чтобы кто-то еще прокомментировал это, так как это действительно было бы довольно неприятным сюрпризом. Я использую Postgres и просматриваю таблицы в pgAdmin, они также не отображаются как внешние ключи. Это может быть нормально для проекта Rails, но что, если мне нужны другие программы для доступа к базе данных? – tentimes

+0

Это немного неприятно, но я узнал, что есть и причина этого. Rails пытаются как можно больше абстрагироваться от db, так что вы можете легко переключать слой persistence. Но я думаю, что это не слишком напряжено. Если вы хотите, вы всегда можете использовать add_index в полях, которые вы хотите использовать как внешние ключи. Или вы можете написать свои миграции в SQL или, возможно, даже в силовые рельсы, чтобы каким-то образом сделать внешние ключи. Но дело в том, что вы даже не будете искать способ сделать это, если вы не знаете, что рельсы не делают это на первом месте. Это действительно имеет смысл? :-) – Renra

+0

На самом деле я узнал, что есть драгоценный камень под названием «Иностранец», чтобы исправить это! Он также имеет надстройку, называемую Immigrant, которая работает для вашего всего db. Добавление индекса отмечает что-то как внешний ключ? Я этого не знал - я новичок в рельсах;) – tentimes

54

В настоящее время принятый ответ на это не совсем точный, поскольку он не добавляет внешний ключ базы данных. Это просто добавление целочисленных столбцов.

В Rails 4.2.x, текущий подход:

http://guides.rubyonrails.org/active_record_migrations.html#foreign-keys

Создание миграции:

rails generate migration migration_name 

Для существующих столбцов в миграции добавить внешние ключи например:

class MigrationName < ActiveRecord::Migration 
    def change 
    add_foreign_key :business_hours, :businesses 
    add_foreign_key :businesses, :users 
    end 
end 

Для Rails 4.x или если вы хотите добавить новый столбец и хотим, чтобы внешний ключ вы можете сделать это, где вы, вероятно, также требуется указать индекс, как верно, но это не входит в о требовании для внешнего ключа:

http://edgeguides.rubyonrails.org/active_record_migrations.html#creating-a-migration

class MigrationName < ActiveRecord::Migration 
    def change 
    add_reference :business_hours, :business, index: true, foreign_key: true 
    add_reference :businesses, :user, index: true, foreign_key: true 
    end 
end 
+1

Спасибо, что поделились этим Крисом. Я все посмотрел, чтобы понять это. – mack

+0

Это то, чего я ожидал, когда искал разрешение этой проблемы. – Ratinahirana

+1

Есть ли способ указать имя для такого столбца внешнего ключа? У меня уже были ситуации, когда в одной записи было несколько ссылок в одной таблице данных. Это означает, что я ожидаю увидеть (sourceClass, targetClass, fieldName), но, как представляется, приведенный выше пример содержит (sourceClass, targetClass). У кого-нибудь есть информация об этом? –

2

Rails 5 теперь можно добавить внешний ключ в миграции см http://devdocs.io/rails~5.0/activerecord/connectionadapters/schemastatements#method-i-add_foreign_key.Так

add_foreign_key :articles, :authors 

создает

ALTER TABLE "articles" ADD CONSTRAINT fk_rails_e74ce85cbc FOREIGN KEY ("author_id") REFERENCES "authors" ("id") 

Если у вас не модели стандарта данных вы можете сделать.

add_foreign_key :articles, :users, column: :author_id, primary_key: "lng_id" 

, который создает

ALTER TABLE "articles" ADD CONSTRAINT fk_rails_58ca3d3a82 FOREIGN KEY ("author_id") REFERENCES "users" ("lng_id") 
Смежные вопросы