Stop rails controller method execution if xhr request is cancelled? Rails API - ruby-on-rails

I'm trying to create an SPA with react frontend and a rails API, and I managed to stop the request from the javascript side, with that in mind, I notice that even if I cancel the request, the rails server stills performs the stuff inside the controller.
def index
#dashboards = Dashboard.all
# Rest of controller logic, like calls to an external API
render json: json_response(#dashboards)
end
Is there a way to catch that the xhr request was cancelled so I can do something like this:
def index
#dashboards = Dashboard.all
if request.cancelled? throw :abort
# It should not matter since request was cancelled in the frontend
render json: json_response(#dashboards)
end

No, sorry, even with a stateful connection like websockets there's no way to reliably detect when that connection is dropped.

Related

Session retaining stale values when using Angular $http.post?

From what I have been seeing in my app, if I my controller using an AngularJs $http.get request, I can't update session data in the controller that handles this request because a render :json=> data type response doesn't update the session cookie on the client. I'm not sure that is actually true, but that what seems to be happening.
If it is true though it seems like if I use devise, for example, and initialize a a session variable, e.g. session[:foo]="bar" in session#create, and then subsequently I have an angular module which executes a $http.get, which is handled by, say, account#my_method, as follows
def my_method
session[:foo]="baz"
[do something]
render :json => {status: "OK"}
end
the session[:foo] change will not be persisted in the user's session cookie thus the next time the user hits a controller session[:foo] will still equal "bar", not "baz".
It seems unlikely, but that looks like what I'm seeing as I debug my application. If so would using a database or memcache session store work better, since the change would happen server side and would not require updating the client side cookie? Or is there a way to handle session updates when using Ajax type methods like $http.get in AngularJs

How to call method after render?

I need to do request on remote service after rendering the page
My controller:
after_filter :remote_action, only: :update
def update
#res = MyService.do_action foo, bar
return render json: #res[:json], status: #res[:status] unless #res[:success]
end
def remote_action
# There is remote http request
end
I need to call remote_action method after rendering the page
after_filter is run after the template has been converted into html, but before that html is sent as a response to the client. So, if you're doing something slow like making a remote http request, then that will slow your response down, as it needs to wait for that remote request to finish: in other words, the remote request will block your response.
To avoid blocking, you could fork off a different thread: have a look at
https://github.com/tra/spawnling
Using this, you would just change your code to
def remote_action
Spawnling.new do
# There is remote http request
end
end
The remote call will still be triggered before the response is sent back, but because it's been forked off into a new thread, the response won't wait for the remote request to come back, it will just happen straight away.
You could also look at https://github.com/collectiveidea/delayed_job, which puts jobs into a database table, where a seperate process will pull them out and execute them.

Raiils: Respond and close HTTP request, but run some more of an action without a queue

(I know it's not best practice, but I'm still wondering if there's a way to do it)
I have a controller action that has a moderately long-running part (~30 seconds). I'd like to respond to the HTTP request (so that it closes), run the part that takes time, then use something like Pusher to notify that it's successful (last part is done, but here for context).
Something like this:
def some_action
if action_should_succeed?
head :no_content
else
render text: "Some error message", status: :unproccessable_entity
end
# Connection is now closed and the client has received the HTTP response
do_long_thing()
send_notification()
end
I know that the "correct" way to do this is to have a job queue and a worker process, but while this is the only action with this kind of delayed processing, I'd prefer not to add all that. Any ideas?

In rails 4 - how to process data from a controller into jquery for purposes of a progressbar

I'm new to rails and jquery/css and webapps in general. I need guidance in building progress bar functionality. My rails app basically inserts file data into an elasticsearch engine. The data is a user's uploaded csv/excel file.
From my controller, what is the best/cleanest way to get progress-bar type percentage from the controller into a coffeescript or jquery code. I'm clueless about how status-percentage type data from the server can be rendered in the view. Below I have the controller that is of relevance. The #upload page has a button that triggers the import action. The import action renders index action once the data is loaded into elasticsearch.
The FileProcessorService is just a ruby class that does the parsing of the file and inserting each record into elasticsearch and returns data.
Here is my controller:
class FileProcessorController < ApplicationController
def index
end
def import
initialize_processor(params[:file])
if (#file_sample != nil || #index_name != nil) then
render 'index'
end
end
def upload
end
def initialize_processor(file_in)
File.open(Rails.root.join('public', 'uploads', file_in.original_filename), 'wb') do |file|
file.write(file_in.read)
end
#file_processor = FileProcessorService.new(file_in)
#file_sample = #file_processor.present_data_sample()
#index_name = #file_processor.load_index()
end
end
Since you mention you're "clueless" about how to approach this, I'll give you some ideas:
Progress
To handle a "progress bar", you're going to need away to receive regular updates at intervals. I don't know if FileProcessorService will do this - but your controller will need to send updates to your JS front-end somehow
Even if you don't have a percentage-based update from your controller, you'll want some event triggers to send updates to your system
Asynchronous
What you're dealing with is called an "asynchronous" request. This is a request outside the normal scope of HTTP requests, whereby your browser will initiate technology such as Javascript to send a request on your behalf
This basically means no refresh for the browser
You'll have to send an asynchronous request via JS, and then listen for the response. The response will be what determines your progress bar status
Pub/Sub
Asynchronous functionality gives you two "methods" to send/receive data - ajax (single request) or pub/sub (multiple requests). Pub/sub is basically how every chat application sends data -- each user gets their own "channel" and the server sends updates to it
I would recommend using a Pub/Sub service called Pusher to achieve the "live" data updates, which you can tie to the progress bar's status
Code
I've not done this before, but this is what you'd need:
You'll need to send events from your controller to a pub/sub channel (Pusher highly recommended)
The user's browser will "listen" to the updates through Pusher - allowing you to assign progress bar status each time an update is
posted

Rails HTTParty Getting Timeout::Error

I have an API centric application (/api/v1/users) it simply return all users restfully with JSON format.
My problem is, if I call that route on the controller, it returns "Timeout::Error"
What is the problem?
class BaseController < ApplicationController
def index
return HTTParty.get('http://localhost:3000/api/v1/users').body
end
end
Update
users_controller.rb (/api/v1/users)
application_controller.rb
https://gist.github.com/4359591
Logs
http://pastie.org/5565618
If I understand correctly, you have an API end-point, at /api/v1/users, and your BaseController#index is calling that method?
If that is correct, inside the same rails process, and you are testing in development mode (as I can tell from your url), then you only have a single process running, which can only handle a single request at once. So if you start a request to BaseController#index, it will start another request to your own test-server, which is busy, and it will just wait until it times out.
If you want to test your API, I would look at a client tool like e.g. Postman.
HTH.

Resources