Создать таблицу соединений без первичного ключа - PullRequest
12 голосов
/ 22 октября 2010

У меня есть две таблицы с отношением "многие ко многим", которые я использую has_and_belongs_to_many для определения ассоциации.

class Foo < ActiveRecord::Base
  ...
  has_and_belongs_to_many :bar
  ...
end

class Bar < ActiveRecord::Base
  ...
  has_and_belongs_to_many :foo
  ...
end

У меня также есть класс, определенный для представления таблицы объединения

class BarFoo < ActiveRecord::Base
  ...
  belongs_to :foo
  belongs_to :bar
  ...
end

Когда я запускаю rake db: seed, я получаю следующую ошибку:

Primary key is not allowed in a has_and_belongs_to_many join table (bar_foo)

Если я редактирую базу данных и удаляю поле первичного ключа (ID) из таблицы bar_foo, а затем снова запускаю rake db: seed allработает как нужно.

Учитывая вышесказанное, что является предпочтительным способом создания таблиц соединения в рельсах без первичного ключа?

Я также пытался использовать "has_many: bars,: through =>:foo "и наоборот, но получил сообщение об ошибке что-то вроде" неопределенного метода 'klass' для nil: NilClass ".

Ответы [ 3 ]

24 голосов
/ 22 октября 2010

Да, первичный ключ не разрешен для has_and_belongs_to_many.

У вас есть 2 способа решить эту проблему:

Удалить первичный ключ в этой таблице.В вашем классе миграции:

create_table :bar_foo, :id => false do |t|
  t.integer :bar_id
  t.integer :foo_id
end

Кроме этого, вам придется удалить файл bar_foo.rb из app/models, а также удалить все файлы фикстуры и тестовые файлы, которые могли быть сгенерированы.Хорошая идея - вызвать script/destroy (или rails destroy), чтобы уничтожить файлы и затем восстановить миграцию.

Или преобразовать в has_many :through

class Foo < ActiveRecord::Base
  ...
  has_many :bar_foos
  has_many :bars, :through => :bar_foos
  ...
end

class Bar < ActiveRecord::Base
  ...
  has_many :bar_foos
  has_many :foos, :through => :bar_foos
  ...
end

class BarFoo < ActiveRecord::Base
  ...
  belongs_to :foo
  belongs_to :bar
  ...
end
4 голосов
/ 21 октября 2011

Вам не нужна модель

class BarFoo < ActiveRecord::Base
  ...
  belongs_to :foo
  belongs_to :bar
  ...
end

, ассоциация has_and_belongs_to_many будет искать в вашей базе данных таблицу с именем bar_foo, и вам нужно сгенерировать миграцию для создания этой таблицы.

rails генерируют миграцию add_table_bar_foo_for_association

, затем вы редактируете свою миграцию, и она должна выглядеть следующим образом

class AddTableBarFooForAssociation < ActiveRecord::Migration
  def up
    create_table :bar_foo, :id => false do |t|
        t.references :bar
        t.references :foo
    end
  end

  def down
    drop_table :bar_foo
  end
end

Теперь ваша ассоциация должна работать, а также, если вам нужна ассоциация, чтобы иметьдополнительные атрибуты в соединении вы можете использовать способ has_many :through и создать модель, связанную с этим.

4 голосов
/ 22 октября 2010

Если вы хотите использовать ассоциацию HABTM, вы не должны создавать модель для нее - просто таблица bars_foos с bar_id и foo_id целочисленными столбцами.

Если вам нужна промежуточная модель (например, если вы хотите отслеживать created_at или некоторые другие атрибуты отношения), вы можете добавить дополнительную модель, например. Barred и тогда у вас будет:

class Foo < ActiveRecord::Base
  ...
  has_many :bars, :through => :barred
  ...
end

class Bar < ActiveRecord::Base
  ...
  has_many :foos, :through => :barred
  ...
end

class Barred < ActiveRecord::Base
  has_many :bars
  has_many :foos
end
...