Building Relationships Between Rails Models

Contributed by Brian Leonard, maintained by Gail Chappell
December 2007
[Revision number: V6.0-2]

This tutorial describes how to build relationships (one-to-one and one-to-many) between models in a NetBeans Ruby on Rails project.

Contents

Tutorial Requirements
Creating the Sample Database
Creating the Comment Model
Migrating the Database
Defining a Relationship Between the Comment and Post Models
Modifying the Controller Scaffolding
Modifying the View to Display Comments
Displaying the Comments
Content on this page applies to NetBeans IDE 6.0

Tutorial Requirements

This tutorial requires the following technologies and resources:

Creating the Sample Database

This tutorial builds on the tutorial Creating a Ruby Weblog in 10 Minutes. If you completed that tutorial, you can start with the project that you built when you finished the tutorial and proceed to the next section. Otherwise, download the RubyWebLog.zip file and follow these steps to create the sample database.

Note: This tutorial uses the MySQL database server. See Installing and Configuring Ruby Support for information about using a MySQL database server in a Ruby application. This document also describes how to use the Java DB database server instead.
  1. Open a command window.
  2. If it has not already been started, start the MySQL database server.
  3. Type the following command to create the development database and press Enter.
    mysqladmin -u root -p create rubyweblog_development
    Note: If the root user does not have a required password, omit the -p argument.
  4. Open the rubyweblog project in the IDE.

    Note: The first time that you open or create a Ruby project in the IDE, the IDE checks if you have any other Ruby installations in addition to the bundled JRuby software. If you do, the IDE displays a dialog box asking you to select which software to use. Choose JRuby if you want to use the bundled JRuby interpreter, or choose your Ruby installation if you prefer to use it instead. For more information, see Configuring the IDE to Use Your Own Ruby Installation in the Installing and Configuring Ruby tutorial.
  5. If your database requires a password, edit the database.yml file and provide the password under the development configuration. Save the file.

    To quickly access the database.yml file, press Alt+Shift+O (Ctrl+Shift+O on the Mac), type database.yml in the File Name text field, and press Enter.
  6. Right-click the rubyweblog node and choose Migrate Database > To Current Version.

    This action updates the database to include the posts table and then adds a body field. The Output window indicates when the migration is complete.

Creating the Comment Model

This tutorial enhances the rubyweblog project by enabling readers to add comments to a blog post. You begin by creating the Comment model to store instances of readers' comments. The project already includes a Post model for storing instances of blog posts.
  1. In the Projects window, expand the rubyweblog node if it is not already expanded, right-click the Models node, and choose Generate.

  2. Type Comment in the Arguments field and click OK.

    The Rails Generator creates a model named Comment. This model includes the following files:

Migrating the Database

Here you add information to the migration file so that each instance of a reader's comment has, in addition to the automatically created id column, the id of the parent post, a time of creation, and a text description.
  1. In the Output window, click the link for the 003_create_comments.rb file.

    The file opens in the editing area.
  2. Add the following code (shown in bold) to create_table in the self.up method:

    Code Sample 1: self.up method
    class 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; and comment, which contains a text description.
  3. Choose File > Save All.
  4. 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

You now have two models in the application: the Post model, which creates a new blog post, and the Comment model, which adds a comment to a blog post. Here you define a relationship between the two models so that a comment is associated with a single post, and a post can contain multiple comments.
  1. Expand the Models node and open post.rb.
  2. Add the following has_many association to post.rb:

    Code Sample 2: has_many association in post.rb
    class Post < ActiveRecord::Base
      has_many :comments
    end
    

    The has_many method indicates that the post can have zero, one, or more comment records associated with it.
  3. Open Models > comment.rb and add the belongs_to association:

    Code Sample 3: belongs_to association in comment.rb
    class Comment < ActiveRecord::Base
      belongs_to :post
    end
    

    The belongs_to method indicates that a comment can be associated with only one post. By default, ActiveRecord uses the post_id  to associate a comment with the post that has a matching post.id.

Modifying the Controller Scaffolding

Next you work with the controller, blog_controller.rb, which generates the scaffolding, or the basic interface for creating, reading, updating, and deleting entries in the blog post.
  1. Expand Controllers node and open blog_controller.rb.

    The controller has all of the scaffold actions, including index, list, show, new, create, edit, update, and destroy.
  2. Modify the show action as shown in the following code sample to save the post_id to the flash:

    Code Sample 4: show action
      def show
        @post = Post.find(params[:id])
        flash[:post_id] = @post.id
      end

    The code finds the post associated with the id parameter passed in with the request. It then stores the id 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).
  3. Scroll to the end of the blog_controller.rb file and add the following post_comment action before the final end statement:

    Code Sample 5: post_comment action
    def 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
      end

    The post_comment action is called when the user clicks the Post button to submit a comment. The first block of code gets the post_id from the flash (which is something like 1, 2, or so on) and uses it to find the blog post associated with that id. The code then creates a new Comment object to be associated with that post_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 the show.rhtml page. This page reloads the post and all of its comments, including the new one.

Modifying the View to Display Comments

Here you edit the show.rhtml file, which displays an individual blog entry.
  1. Expand Views > blog and open show.rhtml.
  2. Add the following code at the end of show.rhtml:

    Code Sample 6: Code for show.rhtml
    <hr>
    <h4>Comments</h4>
    
    <% form_tag :action  => 'post_comment' do %>
    <p><label for="comment_comment">Comment</label><br/>
    <%= text_area 'comment', 'comment' %></p>
    <%= 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. The post_comment action is called when the form is submitted.
  3. Save your files and run the application. If there are no new posts, create a new one.
  4. 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, Without Comments

    View Of Comment Model, But Without Comments

Displaying the Comments

The blog does not yet display the comments that a reader adds, so here you fix that problem.
  1. In blog_controller.rb, find the show action and insert the following post_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
  2. Modify show.rhtml by copying and pasting the contents of the following <ul> tag to just after the <h4>Comments</h4> line:

    Code Sample 8: Code for show.rhtml
    <ul>
    <% for comment in @post_comments %>
    <li><%= comment.comment %><br>
      <div style="color: #999; font-size: 8pt">
          Posted on <%= comment.created_at.strftime("%B %d, %Y at %I:%M %p") %>
      </div>
    </li>
    <% end %>
    </ul>
    
    

    This code stylizes the comments, displays them in a bulleted list, and includes the date and time that the comment was posted.
  3. 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

Next Steps


Send Us Your Feedback