Леса ActiveRecord: два столбца одного и того же типа данных
Другой основной вопрос Rails:
У меня есть таблица базы данных, которая должна содержать ссылки на две разные записи определенного типа данных.
Гипотетический пример: я создаю базу видеоигр. У меня есть таблица для "компаний". Я хочу иметь ровно один разработчик и ровно один издатель для каждой записи "Videogame".
Я знаю, что если я хочу иметь одну компанию, я могу просто сделать что-то вроде:
script/generate Videogame company:references
Но мне нужно иметь обе компании. Я бы предпочел не использовать таблицу соединений, так как может быть только ровно два из данного типа данных, и мне нужно, чтобы они были разными.
Кажется, что ответ должен быть довольно очевидным, но я не могу найти его нигде в Интернете.
Ответы
Ответ 1
Просто для того, чтобы немного убирать вещи, в процессе миграции вы также можете:
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"
Это не серьезная проблема, но я нахожу, что по мере добавления количества ассоциаций с дополнительными аргументами становятся менее понятными вещи, поэтому лучше всего придерживаться значений по умолчанию, когда это возможно.
Ответ 2
Я не знаю, как это сделать с помощью script/generate.
Основная идея легче показать без использования script/generate в любом случае. Вы хотите, чтобы в вашей таблице/модели видеоигр два поля содержали внешние ключи для таблицы/модели компаний.
Я покажу вам, что я думаю код будет выглядеть, но я его не тестировал, поэтому я мог ошибаться.
В файле миграции есть:
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
.
Ответ 3
Если существуют какие-либо методы или проверки, которые вы хотите использовать для определенного типа компании, вы можете подклассифицировать модель компании. Это использует метод, называемый наложением на одну таблицу. Для получения дополнительной информации ознакомьтесь с этой статьей: 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)