Рельси мають_і_надовження_то_мало міграції


119

У мене є дві моделі, restaurantі userя хочу виконати співвідношення has_and_belongs_to_many.

Я вже зайшов у файли моделі та додав has_and_belongs_to_many :restaurantsіhas_and_belongs_to_many :users

Я припускаю, що в цей момент я повинен мати можливість зробити щось на кшталт Rails 3:

rails generate migration ....

але все, що я спробував, здається, не вдалося. Я впевнений, що це щось дійсно просте, я новачок у рейках, тому я все ще вчуся.

Відповіді:


260

Вам потрібно додати окрему таблицю приєднання з лише a restaurant_idта user_id(без первинного ключа) в алфавітному порядку .

Спочатку запустіть міграції, а потім відредагуйте створений файл міграції.

Рейки 3

rails g migration create_restaurants_users_table

Рейки 4 :

rails g migration create_restaurants_users

Рейки 5

rails g migration CreateJoinTableRestaurantUser restaurants users

З документів :

Є також генератор, який буде виробляти таблиці приєднання, якщо JoinTable є частиною імені:


Ваш файл міграції (зверніть увагу :id => false; саме це перешкоджає створенню первинного ключа):

Рейки 3

class CreateRestaurantsUsers < ActiveRecord::Migration
  def self.up
    create_table :restaurants_users, :id => false do |t|
        t.references :restaurant
        t.references :user
    end
    add_index :restaurants_users, [:restaurant_id, :user_id]
    add_index :restaurants_users, :user_id
  end

  def self.down
    drop_table :restaurants_users
  end
end

Рейки 4

class CreateRestaurantsUsers < ActiveRecord::Migration
  def change
    create_table :restaurants_users, id: false do |t|
      t.belongs_to :restaurant
      t.belongs_to :user
    end
  end
end

t.belongs_toавтоматично створить необхідні індекси. def changeавтоматично виявить міграцію вперед або назад, не потрібно вгору / вниз.

Рейки 5

create_join_table :restaurants, :users do |t|
  t.index [:restaurant_id, :user_id]
end

Примітка. Існує також опція для імені користувальницької таблиці, яку можна передавати як параметр для створення_join_table, що викликається table_name. Від док

За замовчуванням назва таблиці приєднання походить від об'єднання перших двох аргументів, передбачених create_join_table, в алфавітному порядку. Щоб налаштувати назву таблиці, надайте параметр: table_name:


8
@Dex - Ви просто з цікавості не могли б ви пояснити, чому ви використовуєте другий індекс складених даних, визначений із зворотним порядком стовпців? У мене було враження, що порядок стовпців не має значення. Я не DBA, просто хочу поглибити своє власне розуміння. Дякую!
звичайний

11
@Jimbo Вам це не потрібно, це дійсно залежить від ваших запитів. Індекси читаються зліва направо, тому перший буде найшвидшим, якщо ви шукаєте далі restaurant_id. Друга допоможе, якщо ви шукаєте далі user_id. Якщо ви шукаєте і те, і інше, я думаю, що база даних буде досить розумною, щоб вона потрібна лише одна. Тому я думаю, що другий насправді не потребує складності. Це було більше лише прикладом. Це було питання Rails, однак розміщення в розділі БД дасть більш повну відповідь.
Dex

3
Другий індекс має деяку надмірність - доки ви ставите запити і на restaurant_id, і на user_id, їх порядок у вашому SQL не має значення, і перший індекс буде використаний. Він також буде використаний, якщо ви лише запитуєте на restaurant_id. Другий індекс повинен бути ввімкнено: user_id, і він буде використаний у тих випадках, коли ви лише запитуєте на user_id (що перший індекс не допоможе у зв'язку з порядком його ключів).
Ярдбой

13
У рейках 4 міграція повинна бути rails g migration create_restaurants_usersбез таблиці в кінці.
Fa11enAngel

6
Ви також можете використовувати рейки та міграцію користувача ресторану CreateJoinTableRestaurantUser. Читати guides.rubyonrails.org/migrations.html#creating-a-join-table
eKek0

36

Відповіді тут досить застарілі. Станом на Rails 4.0.2 ваші міграції використовуються create_join_table.

Щоб створити міграцію, запустіть:

rails g migration CreateJoinTableRestaurantsUsers restaurant user

Це призведе до наступного:

class CreateJoinTableRestaurantsUsers < ActiveRecord::Migration
  def change
    create_join_table :restaurants, :users do |t|
      # t.index [:restaurant_id, :user_id]
      # t.index [:user_id, :restaurant_id]
    end
  end
end

Якщо ви хочете проіндексувати ці стовпці, скаментуйте відповідні рядки, і ви готові йти!


2
Я, як правило, прокоментував би один із рядків індексу та додав unique: trueдо нього. Це запобіжить створенню повторюваних відносин.
Toby 1 Kenobi

26

Створюючи таблицю приєднання, уважно зверніть увагу на вимогу, що обидві таблиці необхідно вказати в алфавітному порядку в імені міграції / класі міграції. Це може вас легко вкусити, якщо назви вашої моделі схожі, наприклад, "abc" та "abb". Якби ти бігав

rails g migration create_abc_abb_table

Ваші відносини працюватимуть не так, як очікувалося. Ви повинні використовувати

rails g migration create_abb_abc_table

замість цього.


1
Що стає першим? foo чи foo_bar?
B

1
Побіг у консолі рейки: ["foo_bar", "foo", "foo bar"]. Sort # => ["foo", "foo bar", "foo_bar"] Unix сортування виходить те саме.
Шадофа

6

Для стосунків HABTM вам потрібно створити таблицю приєднання. Існує лише таблиця приєднання, і ця таблиця не повинна мати стовпчик ідентифікатора. Спробуйте цю міграцію.

def self.up
  create_table :restaurants_users, :id => false do |t|
    t.integer :restaurant_id
    t.integer :user_id
  end
end

def self.down
  drop_table :restaurants_users
end

Ви повинні перевірити це посібник з настанов рейки


Я не думаю, що вам потрібна модель, і я не бачу нічого у посиланні про необхідність моделі для стосунків HABTM.
B

1
Щоб пришвидшити створені запити, додайте індекси до полів id.
Мартін Роберт
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.