Slow third party API requests in Rails - ruby-on-rails

I'm building a single page Rails 4 app that uses the Soundcloud and Instagram gems. I have noticed that sometimes these API requests slow down my app. I am unsure on what the best approach/practice is for handling such requests so that they do not adversely effect the performance of my app? I've looked into asynchronous requests, sidekiq and have also found this example: http://www.jonb.org/2013/01/25/async-rails.html
My Index Controller looks like this:
require 'soundcloud'
class HomeController < ApplicationController
def index
# register a new client, which will exchange the username, password for an access_token
soundcloud_client = Soundcloud.new(
:client_id => ENV['SOUNDCLOUD_ID'],
:client_secret => ENV['SOUNDCLOUD_SECRET'],
:username => ENV['SOUNDCLOUD_USERNAME'],
:password => ENV['SOUNDCLOUD_PASSWORD']
)
# Soundcloud
#activity = soundcloud_client.get('/me/favorites').first(12)
# Instagram
#instagram = Instagram.user_recent_media("1111111", {:count => 12})
end
end

maybe a better approach to this, is to load your index as you would, but do not load the list from soundcloud on that index.
Instead have an Ajax call on your view that calls a pure JSON action inside your controller, doing it that way you will serve the page rapidly, and not block on soundclock. You can put a spinner on your view indicating that the page is still loading. Looking into jquery load method.
https://api.jquery.com/load/
good luck.

Related

Accessing Doorkeeper Application Information before login redirect

Explanation
I am wanting to halt the authorization process of a client app (running OAuth2) coming to the parent app (running Doorkeeper) in order to see which client app is requesting a login. That way I can then look up the clientID and dynamically build a custom login screen for the client app. Right now, my client goes to parent, AuthorizationController is called, but before new is called and I can get the params[:client_id], authenticate_resource_owner! is called with a before_action. That then sends the user to the login page if they are not already logged in with the parent. So, before I can get the param, it is being redirected.
Question
The authenticate_resource_owner! is held in a Doorkeeper helper file. I thought that I set it up correctly to bypass the default helper and go to mine where I can try and grab the param and save in sessions before the redirect, but I guess my route is not set up correctly and I can't find any documentation on how to correctly call it. Can anyone help?
Code
Code for setting up the client:
def setup_client
#client = Application.find_by(uid: params[:client_id])
session[:client_name] = #client.name
authenticate_resource_owner!
end
I know that the first 2 lines work as I placed them in the CustomAuthorizationsController with a byebug and it triggered after the login and before redirect back to client and showed the client name stored in a session variable.
In my config/routes.rb
use_doorkeeper do
controllers :applications => 'doorkeeper/custom_applications'
controllers :authorizations => 'doorkeeper/custom_authorizations'
helpers :doorkeeper => 'doorkeeper/doorkeeper'
end
Helper file is located in app/helpers/doorkeeper/doorkeeper_helper.rb
Error
When I start up my server I get:
: from ~/ruby-2.5.0/gems/doorkeeper-5.0.2/lib/doorkeeper/rails/routes/mapper.rb:12:in `instance_eval'
~/settingsParentApp/config/routes.rb:65:in `block (2 levels) in <top (required)>': undefined method `helpers' for #<Doorkeeper::Rails::Routes::Mapper:0x00007ffd539b9c10> (NoMethodError)
Conclusion
Am I even doing this right? Is there a simpler way built into Doorkeeper that I am not seeing to get this information to customize the login screen? Or is there some error that I am not seeing in how I am calling the helper file?
After thinking through my problem in order to ask this question, a solution dawned on me. I tested it out and it worked. I forgot that in a controller, the before_action statements are called in the order they are presented. So, my solution was just to reorder my statements to call the setup_client first before the authenticate_resource_owner!. This set up the session variable before redirecting to the login screen and then allowed me to have the variable available for use.
Code
Within my config/routes.rb file:
use_doorkeeper do
controllers :applications => 'doorkeeper/custom_applications'
controllers :authorizations => 'doorkeeper/custom_authorizations'
end
This custom route bypasses the doorkeeper default authorization controller and goes to a custom one which inherits from the default controller. So, all I need within this custom one is this code:
Found: app/controllers/doorkeeper/custom_authorizations_controller.rb
module Doorkeeper
class CustomAuthorizationsController < Doorkeeper::AuthorizationsController
before_action :setup_client
before_action :authenticate_resource_owner!
def setup_client
#client = Application.find_by(uid: params[:client_id])
session[:client_name] = #client.name
end
end
end
This code is then run before it looks to the Doorkeeper's default AuthorizationsController and thus calls setup_client first. The session variable is then saved and in the login screen I can call it this way:
<%
if session[:client_name].nil?
#client_name = ''
else
#client_name = ' for ' + session[:client_name]
end
#page_name = "Login" + #client_name
%>
And then in header of the page I call this within the HTML:
<h1><%= #page_name %></h1>
I may do more fancy things later, like saving client icons/logos and color schemes to make branding specific on the login page, but for now, this basic issue has been resolved. Thank you all for acting as my sounding board and problem-solving ducks... if you know of that reference. :-) Happy Coding!

RESTful API in rails

I am very new to rails and following a tutorial for RESTful API so let me excuse if it is of not very good quality as I am equally a starter for these kind of terminologies as well.
I created a controller kitten with a command rails g controller kitten index
and in the index method I posted this code -
class KittenController < ApplicationController
def index
require 'open-uri'
kittens = open('http://placekitten.com/')
response_status = kittens.status
response_body = kittens.read[559, 441]
puts response_status
puts response_body
end
end
and un commented match ':controller(/:action(/:id))(.:format)' in routes.rb
When i navigate through this - http://localhost:3000/kitten
this is what i am getting in my browser -
Kitten#index
Find me in app/views/kitten/index.html.erb
and this in my command line -->
Now my question why it so although i am expecting it in my browser but the cat is shown in command prompt instead of browser ..i am new to rest resource so please excuse if it is a bad one :(
I don't know what tutorial you're following, but doing this seems like a very odd thing to do for Rails in general and learning RESTful APIs in particular.
Anyway, the puts in your controller outputs text to Ruby's standard out, which is going to be the terminal where the server started. That's why this is appearing in the console rather than in your browser: puts is putting it there.
If you want this to appear in a web page, you'll need to make a view for that controller action. Perhaps following further along your tutorial will get you there: if not, you might want to find a better one.
You should read the Model-View-Controller rails guide.
Controllers provide the “glue” between models and views. In Rails, controllers are responsible for processing the incoming requests from the web browser, interrogating the models for data, and passing that data on to the views for presentation.
Define your variable in the controller and display it in the view:
class KittenController < ApplicationController
def index
#variable = 'Hello World'
end
end
In your view (app/views/kitten/index.html.erb):
<%= #variable %>
Rails controllers setup responses with a render call.
When the call is not performed it instantiates the appropriate view and renders that view. In your case that is index.html.erb
Try this:
render :text => kittens.read[559, 441], :status => kittens.status

Prevent Rails app from responding to unintended AJAX request from jQuery

I've built out a fairly complex Rails (2.3.8) app with a lot of jQuery ajax requests. There is an occasional bug, which I have difficultly replicating, where a jQuery $.ajax({..}) request will request a page it shouldn't (like the dash page, which is never called with an ajax request)...
What ensures is absolutely madness. Incredibly strange and terrible errors happen.
For at least a stopgap solution (the app is in production), how can I set up a before filter than will detect any unsolicited xhr/ajax request (or ANY such request on the given controller actions) and kill it before it hits the controller?
In any controller:
before_filter :stop_ajax, :only => [:dashboard]
application_controller.rb:
def stop_ajax
if request.xhr?
render :file => "#{Rails.root}/public/404.html", :status => 404
end
end

How to cache render :json

I have a controller index action which returns json output.
render :json => my_array.to_json
What type of caching do I have to use here. Does 'page caching' make sense for this.
Or do I have to do action caching like below
caches_action :index
Either action caching or page caching would work fine; page caching would have the benefit of never calling the Rails stack, but it depends on whether you need to control who accesses that Json feed.
I'm a big fan of using page caching if you can get away with it - there are big savings on system resources to be had. :)
EDIT: Page caching example, in case there was any confusion:
class SomeController < ApplicationController
caches_page :index
def index
render :json => my_array.to_json
end
end
Unless I've misunderstood something, that should be all you need to do.
Same considerations should apply to JSON as any other output. If you need to validate access to the data for the user, then action caching is the way to go, otherwise page caching should be fine.
If the data changes due to logic in your app, then both forms of caching are problematic and you are better off using something else.

Migrating from Drupal to Rails - Routing

I've developed a new Ruby on Rails site for my organization. I want the new Rails site to intercept incoming requests that were meant for the old site and display a message for the user indicating that the new site is launched, a link the new URL they were most likely trying to get to, and a reminder to update bookmarks.
So I'm pretty green when in comes to rails routing so I'm asking how would you do this. Is there a 'rails way'?
Here are my thoughts so far.
The old site does not use clean urls so every request goes to the default route which in the new site is the home controller with a query string. I was thinking in the controller I can test to see if params[:q] is set and then depending on what the q parameter is, search for and render the an info page directing the user to the new link. If the q parameter doesn't make sense (I don't care about catching every page on the old site, just the important ones) redirect to a custom 404 page informing the user that the link was probably for the old site, and give the user a search page.
Any thoughts, is there a better way?
I appreciate any input.
Thanks
In your Rails controller responsible for the homepage (let's say it's HomeController) add before_filter like so:
class HomeController < ActionController::Base
before_filter :handle_drupal_requests, :only => :index
Then add the handler method itself handle_drupal_requests like so.
class HomeController < ActionController::Base
before_filter :handle_drupal_requests, :only => :index
# ... other code ...
private
def handle_drupal_requests
if params[:q].present?
flash[:notice] = "You're being redirected because blah."
redirect_to convert_drupal_url(params[:q]), :status => 301
end
end
def convert_drupal_url(query_string)
# your logic for converting query string, for example:
item, id = query_string.split('&').last.split('=')
item_controller = item.underscore.split('_').first.pluralize
{:controller => item_controller, :action => "show", :id => id}
end
end
Is there a consistent way that the URLs have changed? Such as /?q=pie becoming /dessert/pie ?
If not, and it requires some sort of manual db query, you'll have to do it the way you mentioned. I would create a redirect action that catches all the paths to keep it separate from your home/index action.
Also, if you care about SEO juice, make sure to use a 301 redirect:
redirect_to dessert_url, :status=>301
You would then have to do an instant redirect (no intermediate page saying 'update your bookmark'). What I would do is the instant redirect, and put a flash[:notice] message saying to "please update your bookmarks".
Please post some examples of URLs if you need more direct examples.

Resources