Search code examples
ruby-on-railsformtasticnested-attributes

rails nested_attribute


I want to create a comment form at the bottom of a blog entry. The problem is that it doesn't save the blog_id so while the comment is created, it isn't assigned a blog_id. I thought that by having this line:

@new_comment = @blog.comments.build(params[:comment])

that it would work but it doesnt. This is what I have:

blog#show

def show
 @blog = Blog.find(params[:id])
 @new_comment = @blog.comments.build(params[:comment])
end

blog#form

...
<%= semantic_form_for @new_comment do |f| %>
  <%= f.input :name %>
  <%= f.input :content, :label => "Comment", :input_html => { :rows => 6, :class => "xxlarge" } %>
<div class="pull-right"><%= f.commit_button :button_html => {:class => "primary"}, :label => "Submit" %></div>
<% end %>

blog.rb

 accepts_nested_attributes_for :comments

comments controller

  def create
@comment = @blog.comments.build(params[:comment])
if @comment.save
  redirect_back_or show_blog_path(@blog)
else
  redirect_to show_blog_path(@blog)
end
end

EDIT:

I nested the form inside the @blog by doing:

<%= semantic_form_for @blog do |f| %>
<%= f.semantic_fields_for :comments do |ff| %>
  <%= ff.input :name %>
   <%= ff.input :content, :label => "Comment", :input_html => { :rows => 6, :class => "xxlarge" } %>
<% end %>    
<div class="pull-right"><%= f.commit_button :button_html => {:class => "primary"}, :label => "Submit" %></div>
<% end %>

and changed the blogs#show to:

@blog = Blog.find(params[:id])
@blog.comments.build
@comments = Comment.where(:blog_id => @blog.id)

Everything works fine, but now after I submit the comment, the comment shows up twice. It shows up in the comments section where it is supposed to and it also shows up as a prepopulated comments form on top of a new comments form. So you see the content of the blog, the prepopulated comment form that I just submitted, a new comments form, and the comment in the display comments section.

I don't know what that it.


Solution

  • You are not referencing the parent object in your form. Yes, you have initialised @new_comment which references the current @blog, but the comment form does not specify this. If you inspect the params passed to create action of comments controller, you are most likely to find no bold_id being passed.

    Try doing

    f.hidden :blog 
    

    in the comment form.

    Or, if you do not wish to have a hidden field as such, then you can have a nested form as

    semantic_form_for [@blog, @new_comment] do |f|
    

    But, this requires your routes file to have paths for comments to be nested under blogs, something as(lets take only the create action for now)

    resources :blogs do
       resources :comments, :only => [:create]
    end
    

    This is required as the form's post is directed to blog_comments_path.

    Hope this helps.

    EDIT : This is how I suggest implementing it (ymmv, so, please be clear if it satisfies your needs) -

    blogs#show as :

    @blog = Blog.find(params[:id])
    @now_comment = @blog.comments.build 
    @comments = @blog.comments # existing comments u might wanna show below the post
    

    The form as :

    = semantic_form_for [@blog, @new_comment] do |f|
       # input for name and content
    

    Routes - nested as shown above

    comments#create as : (blog_id is passed as params too. So, you can find the blog and build a comment based on comment params for that blog and then save it)

    @blog = Blog.find(params[:blog_id])
    @comment = @blog.comments.new(params[:comment])
    @comment.save