Скаффолдинг ActiveRecord: два столбца одного типа данных - PullRequest
23 голосов
/ 06 января 2009

Еще один базовый вопрос Rails:

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

Гипотетический пример: я делаю базу данных видеоигр. У меня есть таблица для «Компании». Я хочу иметь ровно одного разработчика и ровно одного издателя для каждой записи «Видеоигры».

Я знаю, что если я хочу создать одну компанию, я могу сделать что-то вроде:

script/generate Videogame company:references

Но мне нужны обе компании. Я бы предпочел не использовать таблицу соединений, поскольку может быть только два данных данного типа, и мне нужно, чтобы они были различны.

Кажется, ответ должен быть довольно очевидным, но я нигде не могу найти его в Интернете.

Ответы [ 3 ]

46 голосов
/ 06 января 2009

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

create_table :videogames do |t|
  t.belongs_to :developer
  t.belongs_to :publisher
end

И так как вы вызываете ключи developer_id и publisher_id, модель, вероятно, должна быть:

belongs_to :developer, :class_name => "Company"
belongs_to :publisher, :class_name => "Company"

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

9 голосов
/ 06 января 2009

Понятия не имею, как это сделать с помощью сценария / создания.

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

Я покажу вам, как я думаю код будет выглядеть, но я не проверял его, поэтому могу ошибаться.

Ваш файл миграции имеет:

create_table :videogames do |t|
  # all your other fields
  t.int :developer_id
  t.int :publisher_id
end

Тогда в вашей модели:

belongs_to :developer, class_name: "Company", foreign_key: "developer_id"
belongs_to :publisher, class_name: "Company", foreign_key: "publisher_id"

Вы также упоминаете, что хотите, чтобы две компании были разными, что вы могли бы обработать в валидации в модели, которая проверяет, что developer_id != publisher_id.

2 голосов
/ 07 января 2009

Если есть какие-либо методы или валидация, которые вы хотите использовать для определенного типа компании, вы можете подразделить модель компании. Это использует технику, называемую наследование одной таблицы. Для получения дополнительной информации проверьте эту статью: http://wiki.rubyonrails.org/rails/pages/singletableinheritance

Тогда вы бы получили:

#db/migrate/###_create_companies
class CreateCompanies < ActiveRecord::Migration
  def self.up
    create_table :companies do |t|
      t.string :type  # required so rails know what type of company a record is
      t.timestamps
    end
  end

  def self.down
    drop_table :companies
  end
end

#db/migrate/###_create_videogames
class CreateVideogames < ActiveRecord::Migration
  create_table :videogames do |t|
    t.belongs_to :developer
    t.belongs_to :publisher
  end    

  def self.down
    drop_table :videogames
  end
end

#app/models/company.rb
class Company < ActiveRecord::Base 
  has_many :videogames
  common validations and methods
end

#app/models/developer.rb
class Developer < Company
  developer specific code
end

#app/models/publisher.rb
class Publisher < Company
  publisher specific code
end

#app/models/videogame.rb
class Videogame < ActiveRecord::Base 
  belongs_to :developer, :publisher
end

В результате вы можете использовать модели Company, Developer и Publisher.

 Company.find(:all)
 Developer.find(:all)
 Publisher.find(:all)
...