Reputation: 11900
In using Javascript, JQuery, and AJAX with Rails we often have a few internal routes/urls that we can call as helpers.
For example if I have a search bar that uses Twitter Typeahead, I might use an internal route like /search/suggestions
that my Javascript can call to pre-load some typeahead suggestions.
How do I prevent routes like this from getting called by an external/public user? It's important that only the "internal app" have access to this route.
I tried to constrain the route to localhost with little luck -
constraints(ip: /127.0.0.1/) do
get "/search/suggestions", to: "search#load_suggestions"
end
Rails complains that it can't find that route, presumably because of the constraint.
ActionController::RoutingError (No route matches [GET] "/search/suggestions"):
actionpack (4.2.2) lib/action_dispatch/middleware/debug_exceptions.rb:21:in `call'
actionpack (4.2.2) lib/action_dispatch/middleware/show_exceptions.rb:30:in `call'
railties (4.2.2) lib/rails/rack/logger.rb:38:in `call_app'
railties (4.2.2) lib/rails/rack/logger.rb:20:in `block in call'
Thanks!
Upvotes: 3
Views: 1318
Reputation: 3057
With browsers anyone can type anything into the url. So how do you stop someone from accessing a url/route/page they have no right to access?
You have to hook the request before the controller executes the action. If the request into the controller is from a valid requestor, then perform the action, otherwise display a message and redirect, or whatever you need.
I have an app where a user can only see their own feeds not anyone elses; only edit their own posts, etc. The user state is maintained by the sessions controller.
Your twitter typeahead requestor will need something to identify itself, a state that can be validated coming into the controller. This can be implemented an a number of ways. I won't try to guess how your app is setup.
In the controller use before_action to test for valid requestor, which in your case is your twitter typeahead:
class YourController < ApplicationController
before_action :validate_access
private
def validate_access
unless twitter_user?
flash[:danger] = "You do not have access to this feature."
redirect_to root_url (whatever redirect you need)
end
end
In the routes I always like to have a catchall redirect for the case someone does type an invalid URL into the browser. If you don't have this and someone hand edits a URL that doesn't exist in your routes, your app crashes with route not found, which is ugly:
routes.rb
# This is a catchall 301 redirect to home (does not help with (e) type errors)
get "*path", to: redirect('/')
There might be other solutions, probably are, but give this idea a try if it seems useful to you. Please let me know if you have any questions.
Upvotes: 1