## Adding a Second Model Now that you’ve seen how a model built with scaffolding looks like, it’s time to add a second model to the application. The second model will handle comments on blog posts. ### Generating a Model Models in Rails use a singular name, and their corresponding database tables use a plural name. For the model to hold comments, the convention is to use the name Comment. Even if you don’t want to use the entire apparatus set up by scaffolding, most Rails developers still use generators to make things like models and controllers. To create the new model, run this command in your terminal: $ rails generate model Comment commenter:string body:text post:references This command will generate four files: * `app/models/comment.rb` – The model * `db/migrate/20100207235629_create_comments.rb` – The migration * `test/unit/comment_test.rb and test/fixtures/comments.yml` – The test harness. First, take a look at `comment.rb`: @@@ ruby class Comment < ActiveRecord::Base belongs_to :post end @@@ This is very similar to the `post.rb` model that you saw earlier. The difference is the line `belongs_to :post`, which sets up an Active Record *association*. You’ll learn a little about associations in the next section of this guide. In addition to the model, Rails has also made a migration to create the corresponding database table: @@@ ruby class CreateComments < ActiveRecord::Migration def self.up create_table :comments do |t| t.string :commenter t.text :body t.references :post t.timestamps end end def self.down drop_table :comments end end @@@ The `t.references` line sets up a foreign key column for the association between the two models. Go ahead and run the migration: $ rake db:migrate Rails is smart enough to only execute the migrations that have not already been run against the current database, so in this case you will just see: == CreateComments: migrating ============ -- create_table(:comments) -> 0.0017s == CreateComments: migrated (0.0018s) === ### Associating Models Active Record associations let you easily declare the relationship between two models. In the case of comments and posts, you could write out the relationships this way: * Each comment belongs to one post * One post can have many comments In fact, this is very close to the syntax that Rails uses to declare this association. You’ve already seen the line of code inside the Comment model that makes each comment belong to a Post: @@@ ruby class Comment < ActiveRecord::Base belongs_to :post end @@@ You’ll need to edit the `post.rb` file to add the other side of the association: @@@ ruby class Post < ActiveRecord::Base validates :name, :presence => true validates :title, :presence => true, :length => { :minimum => 5 } has_many :comments end @@@ These two declarations enable a good bit of automatic behavior. For example, if you have an instance variable `@post` containing a post, you can retrieve all the comments belonging to that post as the array `@post.comments`.
For more information on Active Record associations, see the Active Record Associations guide.
### Adding a Route for Comments As with the `home` controller, we will need to add a route so that Rails knows where we would like to navigate to see `comments`. Open up the `config/routes.rb` file again, you will see an entry that was added automatically for posts near the top by the scaffold generator, `resources :posts`, edit it as follows: @@@ ruby resources :posts do resources :comments end @@@ This creates `comments` as a *nested resource* within `posts`. This is another part of capturing the hierarchical relationship that exists between posts and comments.For more information on routing, see the Rails Routing from the Outside In guide.
### Generating a Controller With the model in hand, you can turn your attention to creating a matching controller. Again, there’s a generator for this: $ rails generate controller Comments This creates four files and one empty directory: * `app/controllers/comments_controller.rb` – The controller * `app/helpers/comments_helper.rb` – A view helper file * `test/functional/comments_controller_test.rb` – The functional tests for the controller * `test/unit/helpers/comments_helper_test.rb` – The unit tests for the helper * `app/views/comments/` – Views of the controller are stored here Like with any blog, our readers will create their comments directly after reading the post, and once they have added their comment, will be sent back to the post show page to see their comment now listed. Due to this, our `CommentsController` is there to provide a method to create comments and delete SPAM comments when they arrive. So first, we’ll wire up the Post show template (`/app/views/posts/show.html.erb`) to let us make a new comment: @@@ html<%= notice %>
Name: <%= @post.name %>
Title: <%= @post.title %>
Content: <%= @post.content %>
<%= notice %>
Name: <%= @post.name %>
Title: <%= @post.title %>
Content: <%= @post.content %>
Commenter: <%= comment.commenter %>
Comment: <%= comment.body %>
<% end %>