ActiveRecord forests: two columns of the same data type

Another core Rails question:

I have a database table that should contain links to two different records of a particular data type.

Hypothetical example: I am creating a video game database. I have a table for "companies". I want to have exactly one developer and exactly one publisher for each Videogame record.

I know that if I want to have one company, I can just do something like:

script/generate Videogame company:references 

But I need to have both companies. I would prefer not to use the connection table, since there can only be exactly two of this data type, and I need them to be different.

It seems that the answer should be pretty obvious, but I can't find it anywhere on the Internet.

+22
ruby ruby-on-rails activerecord scaffolding
Jan 06 '09 at 16:59
source share
3 answers

Just to clean things up a bit, during the migration process you can also:

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

And since you are calling developer_id and publisher_id keys, the model should be:

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

This is not a serious problem, but I find that as you add the number of associations with additional arguments, things become less clear, so it’s best to stick to the defaults whenever possible.

+45
Jan 6 '09 at 18:37
source share

I do not know how to do this with script / generate.

The basic idea is easier to show without using script / generate anyway. You want the two fields in your table / model of video games to contain foreign keys for the table / model of companies.

I will show you what I think the code will look like, but I have not tested it, so I could be wrong.

The migration file has:

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

Then in your model:

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

You also point out that the two companies should be different, which you could handle when validating in a model that verifies that developer_id != publisher_id .

+9
Jan 06 '09 at 17:53
source share

If there are any methods or checks that you want to use for a particular type of company, you can subclass the company model. This uses a method called single table overlay. For more information, check out this article: http://wiki.rubyonrails.org/rails/pages/singletableinheritance

Then you will have:

 #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 

As a result, you could use the Company, Developer, and Publisher models.

  Company.find(:all) Developer.find(:all) Publisher.find(:all) 
+2
Jan 07 '09 at 6:42
source share



All Articles