This is is how I have my models define for a simple blog
def User
has_many :comments, :dependent => :destroy
has_many :posts
end
def Post
belongs_to :user
has_many :comments
end
def Comment
belongs_to :user开发者_如何转开发
belongs_to :post
end
In my Post Controller I have this code so that I can create a comment in the view
def show
@post = Post.find(params[:id])
@comment = Comment.new
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => @post }
end
end
Then in my Comment#create I have this
def create
@comment = current_user.comments.create(params[:comment])
if @comment.save
redirect_to home_show_path
else
render 'new'
end
end
How should I make it so that my comment model can receive the post_id? I have done this in my Post show view as a fix but is there another way that is better?
<%= f.hidden_field :post_id, :value => @post.id %>
There's nothing necessarily wrong with setting the post_id
via a hidden field in your form - however it does mean that people could potentially associate their comment with any random post.
A better way might be to use nested resources for the comments of posts. To do this, set the following in your routes.rb
file:
resources :posts, :shallow => true do
resources :comments
end
Then your form should look like this:
<%= form_for @comment, :url => post_comments_path(@post) do %>
...
<% end %>
Which will mean that the form POSTs to the path /post/[:post_id]/comments
- which means in turn that the post_id is available to the controller as a param:
def create
@comment = current_user.comments.new(params[:comment])
@comment.post = Post.find(params[:post_id])
if @comment.save
...
end
end
This has the advantage of doing a select for the Post using the post id, and if the Post isn't found, an error will be raised.
It might also be worth rewriting that controller method slightly, so that the Post.find comes first:
def create
@post = Post.find(params[:post_id])
@comment = @post.comments.new(params[:comment])
@comment.user = current_user
if @comment.save
...
end
end
Hope that helps.
Yes, there is a better way. Use nested resources as described in the official Routing guide or in the Getting Started guide. The Getting Started guide even covers this exact example of posts and comments!
<%= form_for :comment, :url => post_comments_path(@post) do |f| %>
<%= f.text_field :content %>
<%= f.submit%>
<% end %>
In your comment create action you have
def create
@post = Post.find(params[:post_id])
@comment = @post.comments.build(params[:comment])
@comment.user = current_user #if you are using devise or any authentication plugin or you define a current_user helper method
if @comment.save
......
end
if you are using rails 3, in you config/routes.rb do
resources :posts do
resources :comments
end
the first section of the code should be in your post/show.html.erb
精彩评论