Damir Nurgaliev
Damir Nurgaliev

Reputation: 351

How to send id from controller to js in Rails app

I need to generate a big report file in background. Here is a simple view to create a OrderReport object.

<%= simple_form_for order_report, remote: true do |f| %>
  <%= f.input :start_date, as: :date, html5: true %>
  <%= f.input :end_date, as: :date, html5: true %>
  <%= f.submit "Generate report", id: "test" %>
<% end %>

And that what is going on in the controller:

def create
   order_report = OrderReport.new(order_report_params)
   order_report.user = current_user
   order_report.save

   OrderReportJob.new(order_report).delay.perform

   render nothing: true
end

After user click a submit button this action creates a background process to generate report. I wrote endpoint to check the status of this background job. This JS is a onclick function to Submit buttom by id #test

$.ajax({
      url: report_url,
      success: function(report) {
        if(report.status === 'progress') {
          $("#spin").show();
          $interval = setInterval(checkStatus, 3000);
        }
      }
    });

This is a part of the JS script. It works good, but the final step to send the ID of created OrderReport to this js file. As you can see in the JS script I have a variable report_url - it's already hardcoded and looks like

var report_url = '/order_reports/1'

So the main idea is to catch the ID of created OrderReport, if it's possible, and use it in the JS script. How can I pass it correctly?

Update:

order_report.js

$(function () {
  $('#test').click(function() {
    var report_url = '/order_reports/39'

    $.ajax({
      url: report_url,
      success: function(report) {
        if(report.status === 'progress') {
          $interval = setInterval(checkStatus, 3000);
        }
      }
    });

    function checkStatus() {
      $.ajax({
        url: report_url,
        success: function(report) {
          if(report.status === 'done') {
            clearInterval($interval)
          }
        }
      });
    }
  });
});

Upvotes: 0

Views: 71

Answers (1)

max
max

Reputation: 101976

A more RESTful solution is to use meaningful response codes to tell the client what happened with the request:

def create
   order_report = OrderReport.new(order_report_params)
   order_report.user = current_user

   respond_to do |format|
     if order_report.save
       OrderReportJob.new(order_report).delay.perform
       format.json { head :created, location: order_report }
     else
       format.json { head :unprocessable_entity }
     end
   end
end

head :created, location: order_report returns a 201 - Created response with a location header that contains a url to the created resource.

This lets you listen for the Rails UJS ajax:success and ajax:error events:

<%= simple_form_for order_report, remote: true, html: { class: 'order_report_form', 'data-type' => 'json'} do |f| %>
  <%= f.input :start_date, as: :date, html5: true %>
  <%= f.input :end_date, as: :date, html5: true %>
  <%= f.submit "Generate report", id: "test" %>
<% end %>

$(document).on('ajax:success', '.order_report_form', function(e, data, status, xhr){
  function checkStatus(url) {
    return $.getJSON(url).then(function(data) {
      // some logic here to test if we have desired result
      if (!desiredResult) {
        // never use setInterval with ajax as it does not care
        // if the previous request is done.
        // instead use setTimeout with recursion
        setTimeout(1000, function(){ checkStatus(url) });
      } else {
        // do something awesome
      }
    }
  }
  checkStatus(xhr.getResponseHeader('location'));
});

$(document).on('ajax:error', '.order_report_form', function(){
  alert("Oops");
});

Upvotes: 1

Related Questions