[engines guide] change comments resource generation

Totally didn't like where this section was going, so scrapped it.

Scaffold is great for some things (lol) but nested resources is definitely not one of them.

Best to walk people through how to do it right, as they would in the real world
This commit is contained in:
Ryan Bigg
2011-10-13 18:04:55 +11:00
parent e6b2e7fbea
commit e537a3fcb1

View File

@@ -201,83 +201,62 @@ If you'd rather play around in the console, +rails console+ will also work just
h4. Generating a comments resource
Now that the engine has the ability to create new blog posts, it only makes sense to add commenting functionality as well.
Now that the engine has the ability to create new blog posts, it only makes sense to add commenting functionality as well. To do get this, you'll need to generate a comment model, a comment controller and then modify the posts scaffold to display comments and allow people to create new ones.
To do this, you can run the scaffold generator this time and tell it to generate a +Comment+ resource instead, with the table having two columns: a +post_id+ integer and +text+ text column.
Run the model generator and tell it to generate a +Comment+ model, with the related table having two columns: a +post_id+ integer and +text+ text column.
<shell>
$ rails generate scaffold Comment post_id:integer text:text
$ rails generate model Comment post_id:integer text:text
invoke active_record
create db/migrate/[timestamp]_create_blorgh_comments.rb
create app/models/blorgh/comment.rb
invoke test_unit
create test/unit/blorgh/comment_test.rb
create test/fixtures/blorgh/comments.yml
</shell>
This generator call will generate almost the same files as it did the first time we called it for generating the +Post+ resource, but this time the files will be called things such as +app/controllers/blorgh/comments_controller.rb+ and +app/models/blorgh/comment.rb+.
This generator call will generate just the necessary model files it needs, namespacing the files under a +blorgh+ directory and creating a model class called +Blorgh::Comment+.
There's a few things wrong with how this generator has worked. It would be better if the comments resource was nested inside the posts resource in the routes, and if the controller created new comment entries inside a post. These are two very easy things to fix up.
To show the comments on a post, edit +app/views/posts/show.html.erb+ and add this line before the "Edit" link:
The +resources+ line from this generator is placed into the +config/routes.rb+ by the generator, but you're going to want to have comments nested underneath a post, and so it's a good idea to change these lines in the +config/routes.rb+ file:
<erb>
<%= render @post.comments %>
</erb>
This line will require there to be a +has_many+ association for comments defined on the +Blorgh::Post+ model, which there isn't right now. To define one, open +app/models/blorgh/post.rb+ and add this line into the model:
<ruby>
Blorgh::Engine.routes.draw do
resources :comments
resources :posts
end
has_many :comments
</ruby>
Into these:
<ruby>
Blorgh::Engine.routes.draw do
resources :posts do
resources :comments
end
end
</ruby>
That fixes the routes. For the controller, it's just as easy. When a request is made to this controller, it will be in the form of +post/:post_id/comments+. In order to find the comments that are being requested, the post is going to need to be fetched using something such as:
<ruby>
post = Post.find(params[:id])
</ruby>
Then to get the comments for this post it would be as simple as:
<ruby>
post.comments
</ruby>
Alternatively, the query to fetch the comments in actions such as the +index+ action would need to be changed from +Comment.all+ into +Comment.find_all_by_post_id(params[:post_id])+. However, the first way is cleaner and so it should be done that way.
To fetch the post in the controller, add a +before_filter+ into the controller's class definition like this:
Turning the model into this:
<ruby>
module Blorgh
class CommentsController < ApplicationController
before_filter :load_post
...
class Post < ActiveRecord::Base
has_many :comments
end
end
</ruby>
This +before_filter+ will call the +load_post+ method before every request that comes into this controller. This method should be defined as a +private+ method after all the actions in the controller:
Because the +has_many+ is defined inside a class that is inside the +Blorgh+ module, Rails will know that you want to use the +Blorgh::Comment+ model for these objects.
<ruby>
module Blorgh
class CommentsController < ApplicationController
before_filter :load_post
Next, there needs to be a form so that comments can be created on a post. To add this, put this line underneath the call to +render @post.comments+ in +app/views/blorgh/posts/show.html.erb+:
# actions go here
<erb>
<%= render "comments/form" %>
</erb>
private
Next, the partial that this line will render needs to exist. Create a new directory at +app/views/blorgh/comments+ and in it a new file called +_form.html.erb+ with this content to create the required partial:
def load_post
@post = Post.find(params[:post_id])
end
end
end
</ruby>
With the post being loaded, the queries in the controller need to be altered in order to query within the scope of the relative post. All occurrences of +Comment+ in this controller should now be replaced with +@post.comments+ so that the queries are correctly scoped.
<erb>
<%= form_for [@post, @post.comments.build] do |f| %>
<p>
<%= f.label :text %><br />
<%= f.text_area :text %>
</p>
<% end %>
</erb>
h3. Hooking into application