Forward Advance Learning

Associations Between Models

In a relational database, models are connected to one another.

A Post might have many Comments, an Inventory might have many Items. A Ship might have a Captain.

Relationships in Rails are set in the Model. To connect two things together, we can say:

class Ship < ActiveRecord::Base
has_one :captain
end

Likewise we might say:

class Captain < ActiveRecord::Base
belongs_to :ship
end

To make this work we need a field in our Captain called ship_id

The foreign key always goes on the model with the belongs_to relationship.

Many to One Relationships

Say we have a ship that has a lot of cargo. We can express this like so:

class Ship < ActiveRecord::Base
has_many :cargo_items
end

Then:

class CargoItem < ActiveRecord::Base
belongs_to :ship
end

We need a ship_id field on the CargoItem model.

Many to Many Relationships

We can also model many to many relationships. Say a ship can belong to more than one fleet, and a fleet can have more than one ship.

class Ship < ActiveRecord::Base
has_and_belongs_to_many :fleets
end

Then:

class Fleet < ActiveRecord::Base
has_and_belongs_to_many :ships
end

To make this work, we then need a join table. The join table is named after the two models in alphabetical order, like so:

fleets_ships

This table needs two fields: ship_id and fleet_id

Presto, they are now connected.

Exercise - Add a one to many relation

Use your scaffolded application that you made in the last section. We are going to add a one to many relation.

Think of a model that makes sense to your domain. If you have shipping, you might make a CrewMember. If you have a Blog, you might choose Comments.

Scaffolding

First of all, scaffold the Model model. Refer to the last exercise if you can't remember how to do this.

Comments will need several fields, I'll leave this part up to you, but crucially, comments will need a blog_post_id: integer field. CrewMembers will need a ship_id field. Notice how I highlighted that part.

Now set up the relationships

You'll need to extend your models something like the following:

class BlogPost
has_many :comments
end
class Comment
belongs_to :blog_post
end

Test the association

Drop into the console and check your association. You should be able to call something like:

post = BlogPost.first
post.comments

Validation

Add validation to your comment. A comment needs a blog_post_id to be valid, plus a couple of other fields. Enforce this.

Listing comments

On your blog_posts/show page, or your ships/show page, list all the join models for a particular blog post. Remember you can use @blog_post.comments to get an array of the comments.

Great. You can now create comments from the comments form, and see them when you view a blog but you will need to manually enter the blog_post_id when creating the comment. Let's fix that.

Optional finishing up

Pick from the following:

  • See if you can integrate your comment form right into your blog_post_show page. (tip, in the blog_post_show controller execute:
@comment = Comment.new.

This will let the comment form just work without modifications.)