1

Probably a very simple problem I'm overlooking. I'm building a feature similar to Facebook's "home" page for logged in users. A user can post topics in one form, and that form works perfectly.

There is a comment form under each posted topic. When a user enters a comment and clicks the submit button the comment is created, but it is not shown unless I manually refresh the page. I can't see what I'm doing wrong here.

_form.html.haml

= form_for [topic, Comment.new], remote: true do |f|
  .form-group
    = f.text_area :body, rows: 2, class: 'form-control', placeholder: "Make a comment"
    = f.submit "Post", class: 'f-button primary f-fw-bold post-btn'

I have tried using @topic for this form as well but get the error: undefined method `comments_path'

comments_controller.rb

class CommentsController < ApplicationController
  def create
    puts "TOPICS PARAMS",params[:topic_id]
    @topic = Topic.find(params[:topic_id])
    @comments = @topic.comments

    @comment = current_user.comments.build( comment_params )
    @comment.topic = @topic
    @new_comment = Comment.new

    if @comment.save
      flash[:notice] = "Comment was created."
      redirect_to topics_path
    else
      flash[:error] = "There was an error saving the comment. Please try again."
      redirect_to topics_path
    end
  end

  private
  def comment_params
    params.require(:comment).permit(:body, :topic_id)
  end
end

All of this is rendered in the topics#index path, so here is the topics controller as well.

topics_controller.rb

class TopicsController < ApplicationController
  def index
    @topics = Topic.order(created_at: :desc)
    @comments = Comment.all
    @limited_partners = LimitedPartner.all
    @users = User.all
    @comment = Comment.new
  end

  def show
    @topic = Topic.find(params[:id])
  end

  def create
    @topic = Topic.new(topic_params)
    @topic.user_id = current_user.id if current_user
    @topic.limited_partner_id = current_user.limited_partner_id if current_user
    if @topic.save
      flash[:notice] = "Topic was saved successfully."
      redirect_to topics_path
    else
      flash[:error] = "Error creating topic. Please try again."
      render :new
    end
  end

  def new
  end

  def edit
  end

  def update
  end

  private
  def topic_params
    params.require(:topic).permit(:body, :liked, :limited_partner_id, :user_id, :comment_id)
  end
end

In the index.html.haml file I call the partial like this:

= render partial: 'comments/form', locals: { topic: topic, comment: @comment} 

3 Answers 3

1

You are using remote: true for your form. So the submit will trigger an Ajax request. A javascript response will be returned, but no HTML will be updated by default.

You will need to sprinkle some javascript to update the HTML yourself: bind a callback to the ajax:success event, or use a js view (e.g. app/views/comments/create.js.erb).

Have also a look at Turbolinks 3 (still in development), which can reduce the amount of custom javascript required for partial page updates.

Sign up to request clarification or add additional context in comments.

Comments

1

Your problem likely lies here ...

= form_for [topic, Comment.new], remote: true do |f|

Try this instead

= form_for @new_comment, url: {controller: 'comments', action: 'create'}, method: "post", remote: true do

and be sure your config/routes.rb looks something like this

get "/some-path", to: "comments#create"
post "/some-path", to: "comments#create"

Comments

0

I had to use javascript to get better control over the form and data. So I made a topic.coffee file with this:

$ ->
  $('.new_comment').on 'submit', (event) =>
    form = $(event.target).closest('form')
    topicCommentsId = form.attr('action').replace(/\//g, '_').substring(1)
    owningCommentsSection = $('#' + topicCommentsId)
    formData = form.serialize()
    $.post form.attr('action'), formData, (data) =>
      extractedBody = $(data.substring(data.indexOf('<body')))
      topicComments = extractedBody.find('#' + topicCommentsId)
      owningCommentsSection.html(topicComments.html())
      form.find('[name="comment[body]"]').val('')
      location.reload();
    return false

I removed the remote: true from my form as well and identify each topic in my index.html.haml with this:

.f-grid-row.topic_comments{id: "topics_#{topic.id}_comments"}
    - topic.comments.each do |comment|
        - if comment.topic_id == topic.id || comment.post_id == topic.id
            ...

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.