Question: Rails 4.2 rendering an Array in js.erb results in a crash

Question

Rails 4.2 rendering an Array in js.erb results in a crash

Answers 2
Added at 2016-12-23 02:12
Tags
Question

So, I'm trying to render an Array of objects in my js.erb file. My controller method that's make the array looks like below:

def process_report
  start_date = Date.parse(params[:start_date])
  finish_date = Date.parse(params[:finish_date])
  done = params[:done].to_i
  kind = params[:kind].to_i
  late = to_boolean params[:late]
  @invoices = Invoice.where(due_date: start_date..finish_date,
                            done: done,
                            kind: kind,
                            late: late)
  if params[:approved] != ""
    @invoices = @invoices.reject{ |i| i.status.description != params[:approved] }
  end
  render 'complete_report.js.erb',
         collection: @invoices, format: :js, status: :ok
end

I know it's a little bit ugly this code. I'm intend to refactoring it. So, if the view passes the params[:approved], I reject some objects from the collection. If the view didn't pass this param, the reject method isn't called and @invoices is an ActiveRecord::Relation. As you guys can see at the end of this method, I render an js.erb file. Inside this file, I have this code:

<% @invoices.each do |invoice| %>
  var tableLine = $("<%= escape_javascript (render partial: 'invoice', locals: {invoice: invoice}, formats: :html) %>");
  $("#report_invoice_table").append(tableLine);
<% end %>

The javascript code executes normally when @invoices is an ActiveRecord::Relation. The problems comes up if params[:approved] isn't empty. The reject method filter the objects that I don't want, but returns @invoices as an Array. When it's an Array, the javascript code simply don't execute. I don't even get an error.

So, concluding: why when I passes an ActiveRecord::Relation to the js.erb so it can be rendered, my javascript code works normally and did not when I passes an Array?

I searched a lot and didn't got close of finding the answer. Sorry for the bad english. Feel free to correct me.

Thanks in advance.

Answers
nr: #1 dodano: 2016-12-23 11:12

Try to render it as a collection:

var tableLine = $("<%= j render(partial: 'invoice', collection: @invoices, formats: :html) %>");
$("#report_invoice_table").append(tableLine);
nr: #2 dodano: 2016-12-23 14:12

I find out the problem. In js.erb file, I got the a code that calculates the sum of all invoices after trying to rendering the invoices.

<% @invoices.each do |invoice| %>
  <% puts invoice.inspect %>
  var tableLine = $("<%= escape_javascript (render partial: 'invoice', 
    locals: {invoice: invoice}, formats: :html) %>");
  $("#report_invoice_table").append(tableLine);
<% end %>

<% if @invoices.empty? %>
  $("#report_total_value").css("display", "none");
<% else %>
  $("#report_total_value").css("display", "inline-block");
  $("#report_total_value").text("Total: R$ " + <%= @invoices.sum(:value) %>);
<% end %>

As you can see, I use the .sum method. All the problem was caused because .sum is a method only available to ActiveRecord::Relation. For the Array class, it must use another method.

<% @invoices.each do |invoice| %>
  <% puts invoice.inspect %>
  var tableLine = $("<%= escape_javascript (render partial: 'invoice',
    locals: {invoice: invoice}, formats: :html) %>");
  $("#report_invoice_table").append(tableLine);
<% end %>

<% if @invoices.empty? %>
  $("#report_total_value").css("display", "none");
<% else %>
  $("#report_total_value").css("display", "inline-block");
  $("#report_total_value").text("Total: R$ "
  + <%= @invoices.map{ |i| i.value }.reduce(0, :+) %>);
<% end %>

After changed it, my code works fine.

Source Show
◀ Wstecz