Building Relationships Between Rails Models
Contributed by Brian Leonard, maintained by Gail Chappell
September 2007 [Revision number: V6.0-1]
This tutorial describes how to build relationships (one-to-one and one-to-many) between models in a NetBeans Ruby on Rails project.
Creating the Comment Model
-
In the Projects window, expand the RubyWebLog node if it is not already expanded, right-click the Models node and choose Generate.
-
Type
Comment
in the Arguments field and click OK.The Rails Generator creates a model named Comment. This model includes the following files:
- app/models/comment.rb. A file that holds the methods for the Comment model. This file is opened in the editing area.
- test/unit/comment_test.rb. A unit test for checking the model.
- test/fixtures/comments.yml. A test fixture for populating the model.
- db/migrate/migrate/003_create_comments.rb. A migration file for altering the structure of the database. This file is versioned 003 as the project already has two migration files,
001_create_posts.rb
and002_add_body.rb
, which create and modify the posts table.
Migrating the Database
-
In the Output window, click the link for the
The file opens in the editing area.003_create_comments.rb
file. -
Add the following code (shown in bold) to
create_table
in theself.up
method:Code Sample 1: self.up
methodclass CreateComments < ActiveRecord::Migration
def self.up
create_table :comments do |t|
t.column 'post_id', :integer
t.column 'created_at', :datetime
t.column 'comment', :text
end
end
def self.down
drop_table :comments
end
end
This migration creates a comments table with four fields:id
, which contains an integer,post_id
, which contains an integer;created_at
, which stores the date and time; andcomment
, which contains a text description. - Choose File > Save All.
-
Right-click the RubyWebLog node and choose Migrate Database > To Current Version.
This action updates the the database to include the comments table. The Output window indicates when the migration is complete.
Defining a Relationship Between the Post and Comment Models
- Expand the Models node and open
post.rb
. -
Add the
has_many
association topost.rb
.Code Sample 2: has_many
association inpost.rb
class Post < ActiveRecord::Base
has_many :comments
end
Thehas_many
method indicates that the post can have have zero, one, or more comment records associated with it. -
Open Models >
comment.rb
and add thebelongs_to
association.Code Sample 3: belongs_to
association incomment.rb
class Comment < ActiveRecord::Base
belongs_to :post
end
Thebelongs_to
method indicates that a comment can be associated with only one post. By default, ActiveRecord uses thepost_id
to associate a comment with the post that has a matchingpost.id.
Modifying the Controller Scaffolding
blog_controller.rb
, which generates the scaffolding, or the basic interface for creating, reading, updating, and deleting entries in the blog post.
-
Double-click Controllers > blog_controller.rb to open the
The controller has all of the scaffold actions, includingblog_controller.rb
file in the editing area.index
,list
,show
,new
,create
,edit
,update
anddestroy
. -
Modify the
show
action to save the post_id to the flash.Code Sample 4: show
actiondef show
@post = Post.find(params[:id])
flash[:post_id] = @post.id
end
The code finds the post associated with theid
parameter passed in with the request. It then stores theid
in the flash for later use. The flash is similar to an HTTP session, but across a single request. When you put something in the flash, it is available for the next request, and then is gone (hence the name flash). -
Scroll to the end of the
blog_controller.rb
file and add the followingpost_comment
action before the finalend
statement:Code Sample 5: post_comment
actiondef post_comment
@comment = Comment.new(
"post_id" => flash[:post_id],
"created_at" => Time.now,
"comment" => params[:comment]['comment']
)
if @comment.save
flash[:notice] = 'Comment was successfully added.'
redirect_to :action => 'show', :id => flash[:post_id]
end
endThe
post_comment
action is called when the user clicks the Post button to submit a comment. The first block of code gets thepost_id
from the flash (which is something like 1, 2, or so on) and uses it to find the blog post associated with thatid
. The code then creates a new Comment object to be associated with thatpost_id
, also consisting of the time created and the actual comment. The Rails framework passes the submitted parameters from the page as a hash (params[:comment]), from which the code pulls out the comment parameter (params[:comment]['comment']).Comment is an ActiveRecord class, so calling its save method saves the comment record to the database. The message is then put in the flash. The code calls the
show
action, which loads theshow.rhtml
page. This page reloads the post and all of its comments, including the new one.
Modifying the View to Display Comments
show.rhtml
file, which displays an individual blog entry.
- Expand Views > blog and open
show.rhtml
. -
Add the following code at the end of
show.rhtml
.Code Sample 6: Code for show.rhtml
Comments
<% form_tag :action => 'post_comment' do %>Comment
<%= text_area 'comment', 'comment' %>
<%= submit_tag "Post" %>
<%end %>
This code produces a form that includes a a text input area for writing the comment, and a Submit button labeled Post, as shown in Figure 1. Thepost_comment
action is called when the form is submitted. - Save your files and run the application. If there are no new posts, create a new one.
-
Click a Permalink to view the details of a blog entry. Try adding a comment in the text area, but note that the blog does not yet display comments when you click the Post button.
If your posting is successful, you see a message at the top of the view, as shown in the following figure. In the next steps you add code to collect and display the comments.
Figure 1: View of Comment Model, But Without Comments
Displaying the Comments
-
In
blog_controller.rb
, find theshow
action and insert the followingpost_comments
instance variable to collect the comments:Code Sample 7: Code for blog_controller.rb
def show
@post = Post.find(params[:id])
@post_comments = @post.comments.collect
flash[:post_id] = @post.id
end -
Modify
show.rhtml
by copying and pasting the contents of the following- tag to just after the
Comments
line.Code Sample 8: Code for show.rhtml
- <%= comment.comment %>
Posted on <%= comment.created_at.strftime("%B %d, %Y at %I:%M %p") %>
<% end %>
This code stylizes the comments, displays them in a bulleted list, and includes the date and time that the comment was posted.
Choose File > Save All, then refresh your browser.
The comments now appear in the blog in a bulleted list, as shown in the following figure.
Figure 2: View of Comment Model, With Comments
![Figure 2: View of Comment Model, With Comments](../../../images/articles/60/ruby/model/comment_model_success.png)