Еще один базовый вопрос Rails:
У меня есть таблица базы данных, которая должна содержать ссылки ровно на две разные записи определенного типа данных.
Гипотетический пример: я создаю базу данных видеоигр. У меня есть таблица «Компании». Я хочу иметь ровно одного разработчика и только одного издателя для каждой записи «Видеоигры».
Я знаю, что если я хочу иметь одну компанию, я могу просто сделать что-то вроде:
script/generate Videogame company:references
Но мне нужны обе компании. Я бы предпочел не использовать таблицу соединений, так как может быть только два из данного типа данных, и мне нужно, чтобы они были разными.
Кажется, ответ должен быть довольно очевидным, но я не могу найти его нигде в Интернете.





Я не знаю, как это сделать с помощью 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.
Чтобы немного навести порядок, в процессе миграции теперь вы также можете:
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"
Это не большая проблема, но я считаю, что по мере добавления количества ассоциаций с дополнительными аргументами все становится менее ясным, поэтому лучше по возможности придерживаться значений по умолчанию.
Я пробовал это, и теперь у меня есть developer_id, но нет доступа к game.developer. У меня в моей видеоигре есть класс attr_accessible: developer.
Вероятно, это уже было решено, но добавили ли вы has_many: games (или что-то в этом роде) в свою модель разработчика?
Как сделать обратное сопоставление?
Если есть какие-либо методы или проверки, которые вы хотите использовать для определенного типа компании, вы можете подклассифицировать модель компании. При этом используется метод, называемый наследованием одной таблицы. Для получения дополнительной информации ознакомьтесь с этой статьей: 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.find(:all)
Developer.find(:all)
Publisher.find(:all)
В качестве примечания, параметр foreign_key здесь не нужен, поскольку по умолчанию используется имя ассоциации + "_id". Для получения дополнительной информации см. spacevatican.org/2008/5/6/….