jeudi 9 juin 2016

Rails controller - execute action only if the a Rails UJS method inside succeed (mutually dependent methods)

Following another question (Rails controller - execute action only if the two methods inside succeed (mutually dependent methods)), I would like to ensure that inside one of my controller's action, if the user does not see the message displayed by a Rails UJS method, then the first methods of the controller acion are not implemented either.

CONTEXT

I have a Controller with a method called 'actions'. When the app goes inside the method 'example_action', it implements a first method (1) update_user_table and then (2) another update_userdeal_table. (both will read and write database) and then (3) a third method which is related to a Rails UJS(ajax) call.

My issue is the following: in case of timeout in the middle of the controller, I want to avoid the case where the User table (via method 1) is updated, the UserDeal table is updated (via method 2) but NOT the thrid method i.e the ajax request that displays a message FAILS (error, timeout,...status like 500 or 404 or canceled or timeout...).

In my app, for mobile users if they're in a subway with internet connection, they launch the request that goes through 'example_action' controller, performs successfully the first method (1) and second method (2) but then they enter a tunnel for 60 seconds with very very low (<5b/sec) or NO internet connection, so for UX reasons, I timeout the request and display to the user 'sorry it took too long, try again'. The problem is that if I could not show to them the result (3), I need to be able to not execute (1) and(2).

I need the two methods (1) and(2) and(3) to be "mutually dependent": if one does not succeed, the other one should not be performed. It's the best way I can describe it.

Today Here is my code. It's not working as I am manually testing by clicking and then after just 2 seconds I disconnect the internet connection. I see in my database that (1) and(2) were performed and the databases were updated but I saw the message 'sorry it took too long, try again'.

Is that the right approach ? if yes how to do this? If not, should I try a different angle like: if (1) and(2) were successful but not(3) should I store the fact the rails UJS xhr status was an error or timeout, that consequently the modal wxas not effectively displayed to the user and then show to them the result/message once they get back online?

Here is the code

html page for the user the user click on a button that triggers a Rails UJS aajax request that will display ultimately the modal message

<div id=zone"> 
   <%= link_to image_tag(smallest_src_request),
          deal_modal_path,
           remote: true %>
</div>

This send to a route that points to this controller action

Deal controller

class DealsController < ApplicationController
  def deal_modal
    Deal.transaction do
       update_user_table # that's the (1)
       update_userdeal_table  # that's the (2)
       # show_modal_message
       respond_to do |format|
         format.js
       end  
  end

  private
  def update_user_table
    # update the table User so it needs to connect to internet and acces the distant User table
  end
  def update_userdeal_table
    # update the table UserDeal table so it needs to connect to internet and access the distant UserDeal table
  end
end

This points to a js.erb view file

deal_modal.js.erb

showModalMessage("Here is your result <variable and all>);

To manage the ajax, error, timeouts... (if necessary to the resolution of the question), I use Rails UJS settings.

IMPORTANT: It is here that in case of error or timeout, I send the error / timeout modal message that comes in place of the one you normally get (see just above "Here is your result..")

$(document).on('page:change', function () {
      $("#zone").
        on('ajax:error',function(event,xhr, status, error){
          console.log(' ajax call failed:', error);
          var msg;
          msg = Messenger().post({
            hideAfter:  4, 
            message:    "sorry it took too long, try again."
          });
    });

$(document).on('page:change', function () {
  //set timeout Rails UJS ajax option that will display message for ajax:error cases defined above
  $.rails.ajax = function(options) {
    if (!options.timeout) {
      options.timeout = 5000;
    }    
    return $.ajax(options);
  };
});

Aucun commentaire:

Enregistrer un commentaire