0

Hi I'm fairly new to rails and am trying to implement AJAX in my Rails application.

The problem is that when I submit my form it seems like the create action is definitely called, as when I refresh the page the new element appears, but the table doesn't automatically refresh.

topics/show.html.erb relevant code:

<div class="row" id="toberefreshed">
  <%= render('show_partial', :locals => {:topic => @topic}) %>
</div>

topics/_show_partial.html.erb relevant code:

<table class = "opinionlist" align="center">
  <% opinions = @topic.opinions %>
  <% cons = opinions.select{|opinion| opinion.type_of == 'con'} %>
  <% pros = opinions.select{|opinion| opinion.type_of == 'pro'} %>
  <tr>
    <% pros.each do |pro|%>
      <td>
        <div class="article-body">
          <%= pro.content %>
        </div>
        <div class="article-meta-details">
          <small>
            Created by: <%= pro.user.username %>
            <%= time_ago_in_words(pro.created_at) %> ago,
          </small>
        </div>
      </td>
    <% end %>
    <% if pros.length < cons.length %>
      <% difference = cons.length - pros.length%>
      <% difference.times do %>
        <%= content_tag(:td) %>
      <% end %>
    <% end %>

    <td><%= render 'opinions/form', opinion: Opinion.new, typeOf: "pro", :topic => @topic %></td>
  </tr>
  <tr>
    <% cons.each do |con|%>
      <td>
        <div class="article-body">
          <%= con.content %>
        </div>
        <div class="article-meta-details">
          <small>
            Created by: <%= con.user.username %>
            <%= time_ago_in_words(con.created_at) %> ago,
          </small>
        </div>
      </td>
    <% end %>
    <% if pros.length > cons.length %>
      <% difference = pros.length - cons.length %>
      <%  puts "DIFFERENCE: " + difference.to_s  %>
      <% difference.times do %>
        <%= content_tag(:td) %>
      <% end %>
    <% end %>
    <td>
      <%= render 'opinions/form', opinion: Opinion.new, typeOf: "con", :topic => @topic %>
    </td>
  </tr>
</table>

topics/updated_view.js.erb:

$("toberefreshed").html("<%= escape_javascript(render("topics/show_partial", :locals => {:topic => @opinion.topic})) %>");

opinions_controller.rb

class OpinionsController < ApplicationController
  def create
    @opinion = Opinion.new(opinion_params)
    @opinion.user = current_user
    @opinion.topic = Topic.find(params[:to_find_id])
    @opinion.type_of = params[:type_of]
    if @opinion.save
      flash[:success] = 'Opinion Added'
    else
      puts @opinion.errors.full_messages
      flash[:danger] = 'Opinion not Added'
    end
    respond_to do |format|
      format.js
    end
  end
  private
  def opinion_params
    params.require(:opinion).permit(:content)
  end
end

EDIT: opinions/_form.html.erb

<div class="row">
  <div class="col-xs-12">
    <%= form_for(opinion, :html=> {class:"form-horizontal", role:"form"}, remote: true) do |f| %>
      <div class="form-group">
        <div class="col-sm-12">
          <%= f.text_area :content, rows:4, class: "form-control", placeholder: "Opinion" %>
        </div>
      </div>
      <%= hidden_field_tag 'type_of', typeOf %>
      <%= hidden_field_tag :to_find_id, @topic.id %>
      <% puts "ID: " + @topic.id.to_s %>
      <div class="form-group">
        <div class="col-sm-12">
          <%= f.submit %>
        </div>
      </div>
    <% end %>
  </div>
</div>

Thank you so much for your help, Raahil

1 Answers1

0

In the topics/_show_partial.html.erb

replace

<% opinions = @topic.opinions %> in the second line

with

<% opinions = topic.opinions %>

You are passing the topic variable through locals in to the partial but you are calling instance variable @topic which doesn't exist when you call create method

Also change the following:

<%= render 'opinions/form', opinion: Opinion.new, typeOf: "pro", :topic => @topic %>

To

<%= render 'opinions/form', opinion: Opinion.new, typeOf: "pro", :topic => topic %>


And change

<%= render 'opinions/form', opinion: Opinion.new, typeOf: "con", :topic => @topic %>

To

<%= render 'opinions/form', opinion: Opinion.new, typeOf: "con", :topic => topic %>


So your In the topics/_show_partial.html.erb should look like the following:

<table class = "opinionlist" align="center">
  <% opinions = topic.opinions %>
  <% cons = opinions.select{|opinion| opinion.type_of == 'con'} %>
  <% pros = opinions.select{|opinion| opinion.type_of == 'pro'} %>
  <tr>
    <% pros.each do |pro|%>
      <td>
        <div class="article-body">
          <%= pro.content %>
        </div>
        <div class="article-meta-details">
          <small>
            Created by: <%= pro.user.username %>
            <%= time_ago_in_words(pro.created_at) %> ago,
          </small>
        </div>
      </td>
    <% end %>
    <% if pros.length < cons.length %>
      <% difference = cons.length - pros.length%>
      <% difference.times do %>
        <%= content_tag(:td) %>
      <% end %>
    <% end %>

    <td><%= render 'opinions/form', opinion: Opinion.new, typeOf: "pro", :topic => topic %></td>
  </tr>
  <tr>
    <% cons.each do |con|%>
      <td>
        <div class="article-body">
          <%= con.content %>
        </div>
        <div class="article-meta-details">
          <small>
            Created by: <%= con.user.username %>
            <%= time_ago_in_words(con.created_at) %> ago,
          </small>
        </div>
      </td>
    <% end %>
    <% if pros.length > cons.length %>
      <% difference = pros.length - cons.length %>
      <%  puts "DIFFERENCE: " + difference.to_s  %>
      <% difference.times do %>
        <%= content_tag(:td) %>
      <% end %>
    <% end %>
    <td>
      <%= render 'opinions/form', opinion: Opinion.new, typeOf: "con", :topic => topic %>
    </td>
  </tr>
</table>

One Last thing that you can take as a recommendation:

You are building a lot of logic inside your views take for instance topics/_show_partial.html.erb you create lots of local variables inside the view. I would recommend using another approach like building all your variables in a layer between before the view like presenters check out this discussion about rails presenters

What is the Rails Presenters folder for?

Views should remain simple and free from logic as possible as you can

Moustafa Sallam
  • 1,110
  • 1
  • 9
  • 17
  • When I do that this happens: Showing /topics/_show_partial.html.erb where line #2 raised: undefined local variable or method `topic' for #<#:0xce8af88> Did you mean? @topic – Raahil Jain Jan 06 '19 at 06:10
  • no look at the docs to see how passing local variables to views https://guides.rubyonrails.org/layouts_and_rendering.html#passing-local-variables – Moustafa Sallam Jan 06 '19 at 06:43
  • Ok, so at this point my render statements look like this: render partial: "topics/show_partial", locals: {topic: @opinion.topic} Is this correct? I also renamed the js file to create.js.erb and moved it to opinions like Vasilisa suggested. It still doesn't seem to be replacing the content of my table, but I'm no longer getting the undefined local variable or method error. – Raahil Jain Jan 06 '19 at 20:39