Сложная миграция и моделирование Rails с использованием таблицы самообъединения ": пользователи" и таблицы ": диапазоны": одновременные отношения "один ко многим" и "многие ко многим" - PullRequest
0 голосов
/ 06 февраля 2019

Моя :users таблица успешно объединена со всем необходимым запутанным (для этого новичка) кодом и таблицами, необходимыми для этого.Две группы :users: :teachers и :students.

Мне нужно, чтобы группа :teachers присоединилась один к многим с таблицей :bands (у группы может быть только одна группа).учитель), одновременно объединяя :students многие-ко-многим с таблицей :bands (группа может иметь много учеников и наоборот).

Меня сбивает с толку то, что :students и :teachers оба :users.Поэтому, если на мгновение я притворюсь, что есть только один вид пользователя, и перейду к отношениям «один ко многим (учитель)», то модель Band belongs_to :user и модель User has_many :bands

Но если вместо этого я выберу отношение «многие ко многим (студентам)», то таблица соединения Band модель has_many :users, through :user_bands и таблица соединения User модель has_many :bands, through :user_bands.(UserBands модель имеет belongs_to :user и belongs_to :band в данном случае)

Но мне нужны оба отношения одновременно.На самом деле я не пытался вставить has_many :bands в модель User, одновременно имея has_many :users (через таблицу соединений) и belongs_to :users в модели Bands, потому что, если Rails не более волшебен, чем я считаю,не будет отличаться, что учителя получают один ко многим, в то время как студенты получают многие ко многим.

Я не пытался сделать свою лучшую догадку (ниже), потому что я по общему признанию капризный: моя база данных ужеимеет огромное количество отношений «многие ко многим», которые не повреждены и функционируют должным образом.Однажды, когда я попытался сделать сложное изменение в начале этого процесса, он настолько испортил вещи, что откат и отмена изменений в модели не вернули меня туда, откуда я начал, так что мне пришлось идтивернуться к восстановлению всего с нуля после того, как вытащил достаточно волос для пострижки.На этот раз у меня есть github, поэтому я должен иметь возможность отменить проект, если он взорвется, как раньше, но git - это его собственное суетливое минное поле.

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

  1. В User модели добавить has_many :bands.
  2. В Band модели добавить has_many :students, through :user_bands;добавить belongs_to :teacher
  3. В миграции create_bands добавить t.belongs_to :teacher
  4. В модели UserBands, добавить belongs_to :teacher и добавить t.belongs_to :teacher в миграции create_user_bands.

1 Ответ

0 голосов
/ 06 февраля 2019

Необходимые ассоциации не являются самостоятельными.Самостоятельные объединения в основном используются для построения древовидных иерархий из одной таблицы - см. руководства для хорошего примера .

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

Учителя

class AddTeacherIdToBands < ActiveRecord::Migration[5.2]
  def change
    add_reference :bands, :teacher, foreign_key: { to_table: :users }
  end
end

class User < ApplicationRecord
  has_many :bands_as_teacher, 
    class_name: 'Band',
    foreign_key: 'teacher_id'
end

class Band < ApplicationRecord
  belongs_to :teacher, 
    class_name: 'User'
end

Мы называем ассоциацию bands_as_teacher, чтобы избежать конфликтов и путаницы.Это требует от нас явной установки параметров class_name и foreign_key, поскольку они не могут быть выведены из названия.

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

Учащиеся

Чтобы создать ассоциацию между группой и ее участниками, вам нужна ассоциация m2m через объединяющую таблицу:

class CreateBandMemberships < ActiveRecord::Migration[5.2]
  def change
    create_table :band_memberships do |t|
      t.references :band, foreign_key: true
      t.references :user, foreign_key: true
      t.timestamps
    end
  end
end

class Band < ApplicationRecord
  # ...
  has_many :band_memberships
  has_many :users, through: :band_memberships
end

class BandMembership < ApplicationRecord
  belongs_to :band
  belongs_to :user
end

class User < ApplicationRecord
  # ...
  has_many :band_memberships
  has_many :bands, through: :band_memberships
end

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

class Band < ApplicationRecord
  # ...
  has_many :band_memberships
  has_many :members, through: :band_memberships, source: :user
end

class User < ApplicationRecord
  # ...
  has_many :band_memberships
  has_many :bands_as_member, through: :band_memberships, source: :band
end
...