ruby on rails model method loop - ruby-on-rails

The title is probably not the best, but here is my question. I have a rails model with this method
def stats(event_id)
while true do
sleep 1
response = HTTParty.get (xxx)
response
end
end
I continuously stream the response to the client and then I have a client script that calls this method whenever a user click on another event.
in my head, I think there is an issue. whenever the client script calls this method again, a new instance is created (in the controller) which means i'm streaming 2x to the client (the previous one and the new instance).
How can I get this to work? I need this instance to exist once for each user so no duplicate data is streamed and previous instances for the user should stop whenever a new request is made.
I don't mind moving this to the controller if it helps. Also, you access the streaming page only if you are logged in.
Thanks.

Related

Keep an instance of an object for the whole Rails server?

Essentially, I have a simple class that interacts with a local RPC server. Call it RPC_Class.
Every user the website will host will make requests that require the rails server to make calls to the RPC client.
This class needs to be instantiated as such
rpc = RPC_Class.new('localhost:4325')
And then I make calls to it
puts rpc.getbalance
Now, there are three options:
Create a new instance for every request needed (obviously a bad solution)
Create a new instance for every user's session
Create one instance for the whole server
I think option three is the most performative option. Where do I initialize this class such that I can use it throughout the server code?
I think you should go with Rails caching for handling this use case. You can cache the response when you make the API call the first time and use the cached response for all the calls you receive after that.
You can write a method like this:
def fetch_rpc_balance
Rails.cache.fetch("rpc_balance", expires_in: 24.hours)
rpc = RPC_Class.new('localhost:4325')
puts rpc.getbalance
end
end
Now, if you use the fetch_rpc_balance method in your logic, it will make the API call only the first time and return the cached response from second call onwards.

Can I safely tell Rails to remember the result of an expensive instance method?

My current_user has a has_privilege? method which calls the database to check whether this user has a certain admin privilege or a superceding one (system is similar to Wordpress privileges). As has_privilege? gets called several times per page, can I tell Rails to remember the result for as long as the instance exists, using the method explained at How can I save the value of an instance method?, or would this make the app insecure? It's a bad idea to put this information into the session variable or cache, right?
as long as the instance exists
It depends what you mean by that.
Rails treat each HTTP requests in a separated process so you can cache the has_privilege? method output for the current request (so calling many times the method will query the DB only the first time), but on the next request, it will be executed again and then cached (and actually you want that as you may change the permissions and don't want the user to keep the old permissions).
In order to do so you can use this simple trick:
class User < ActiveRecord
def has_privilege?
#has_privilege ||= begin
# You code here. The returned value will be cached in #has_privilege.
end
end
end
So the first time the method is called, #has_privilege is nil for your instance of the user, so the || will its right side part which is the = begin ... end.
Excepted if the code return nil, the value will be assigned to #has_privilege.
On the next call, #has_privilege is no more nil, therefore || will no trigger its right side part and return immediately.
I need a cross request cache
In this case, you have to go with JWT and save the value in the token.
JWT is a token generated and signed by the server, and it must be sent back in to each requests, otherwise the server will reject it.
As only the server can sign the token, in the case the user tries to change it, the server will reject and sign out the user.
You can read more on their website, it's quite simple to use.

Rails: HTTP Get request from Callback Method (in model)

I want to create a callback in my User model. after a user is created, a callback is initiated to run get_followers to get that users twitter followers (via full contact API).
This is all a bit new to me...
Is this the correct approach putting the request in a callback or should it be in the controller somewhere? And then how do I make the request to the endpoint in rails, and where should I be processing the data that is returned?
EDIT... Is something like this okay?
User.rb
require 'open-uri'
require 'json'
class Customer < ActiveRecord::Base
after_create :get_twitter
private
def get_twitter
source = "url-to-parse.com"
#data = JSON.parse(JSON.load(source))
end
A few things to consider:
The callback will run for every Customer that is created, not just those created in the controller. That may or may not be desirable, depending on your specific needs. For example, you will need to handle this in your tests by mocking out the external API call.
Errors could occur in the callback if the service is down, or if a bad response is returned. You have to decide how to handle those errors.
You should consider having the code in the callback run in a background process rather than in the web request, if it is not required to run immediately. That way errors in the callback will not produce a 500 page, and will improve performance since the response can be returned without waiting for the callback to complete. In such a case the rest of the application must be able to handle a user for whom the callback has not yet completed.

How to Make the Controller wait for a Delayed Job while the rest of the App continues on?

(This question is a follow-up to How do I handle long requests for a Rails App so other users are not delayed too much? )
A user submits an answer to my Rails app and it gets checked in the back-end for up to 10 seconds. This would cause delays for all other users, so I'm trying out the delayed_job gem to move the checking to a Worker process. The Worker code returns the results back to the controller. However, the controller doesn't realize it's supposed to wait patiently for the results, so it causes an error.
How do I get the controller to wait for the results and let the rest of the app handle simple requests meanwhile?
In Javascript, one would use callbacks to call the function instead of returning a value. Should I do the same thing in Ruby and call back the controller from the Worker?
Update:
Alternatively, how can I call a controller method from the Worker? Then I could just call the relevant actions when its done.
This is the relevant code:
Controller:
def submit
question = Question.find params[:question]
user_answer = params[:user_answer]
#result, #other_stuff = SubmitWorker.new.check(question, user_answer)
render_ajax
end
submit_worker.rb :
class SubmitWorker
def check
#lots of code...
end
handle_asynchronously :check
end
Using DJ to offload the work is absolutely fine and normal, but making the controller wait for the response rather defeats the point.
You can add some form of callback to the end of your check method so that when the job finishes your user can be notified.
You can find some discussion on performing notifications in this question: push-style notifications simliar to Facebook with Rails and jQuery
Alternatively you can have your browser periodically call a controller action that checks for the results of the job - the results would ideally be an ActiveRecord object. Again you can find discussion on periodic javascript in this question: Rails 3 equivalent for periodically_call_remote
I think what you are trying to do here is little contradicting, because you use delayed_job when do done want to interrupt the control flow (so your users don't want to want until the request completes).
But if you want your controller to want until you get the results, then you don't want to use background processes like delayed_job.
You might want to think of different way of notifying the user, after you have done your checking, while keeping the background process as it is.

How do I call a controller action on the user exiting the session?

I add a bunch of records to my table during a user`s session. Once the user exits the session (closes the window, goes to a different website etc.) I want to be able to call a function like so:
def clear_list
Shoe.where(user_id: #user_id).destroy_all
end
I know that before_filter enables you to call a controller action as the page loads. What can I use to call an action on page close?
"Destroying a session" and "closing a page" don't mean the same thing.
I guess you're looking for a before_destroy callback for your Session model.
See docs.
Maybe you can do something with jquery here is another question about it: javascript detect browser close tab/close browser, but im not sure you would be able to run code before the page gets closed, you are better off handling sessions and background process.

Resources