Prepend path prefix to all rails routes - ruby-on-rails

I have a setup where nginx serves a rails application inside a specific subfolder
eg. http://myserver/railsapp/ and everything inside gets proxied to rails, if the first subfolder is different, it servers static files from another folder.
I haven't been able to find how to specify this behaviour in rails in an intelligent way. I mean, what I want is to specify an option like Rails.server_prefix = /railsapp so that all the routes get prepended automagically, both on the incoming requests and on the generated links.

You probably want to use the router's scope method with the :path argument:
Rails.application.routes do
scope(:path => '/railsapp') do
# the rest of your routes go here
end
end
See the docs for more info.

Related

Rails - Add a route prefix to a specific directory

I have a messy rails 3 application that's come from a different developer and I need to refactor it.
What I want to do is move the contents of "app" into a subfolder called "classic".
app/classic
And then have all URL's with a classic prefix such as
localhost:3000/classic/wills/new
Route to controllers inside of the "app/classic" folder.
And then every regular url that does not contain the classic prefix - route in the standard way to app/
Is it possible to do this? The only thing I've discovered so far is that I can add a scope inside of my routes file.
scope(:path => '/classic')
But all that does is require a prefix for every URL. I'm really not sure how to go about this!
This is a route namespace. Take a look at this section in Rails Routing from the Outside In: http://guides.rubyonrails.org/routing.html#controller-namespaces-and-routing
namespace :classic do
# your routes here
end
This will do 3 things -
the path to the controller files need to be under /app/controllers/classic/
the name of the controllers need to change to Classic::ControllerName
the url is now /classic/controller/action
This sounds like what you want, but you can modify this to get just the parts you want if you don't want all 3.
In route.rb file:
#Of course, you have to configure the right http method.
get 'wills/new' => 'wills#new', as: 'to_classic_wills_new'
Hope this helps!

How can I restrict the API calls in rails?

I am the admin and multiple people are working on the project. New routes are being created everyday(basically APIs). I want a central record of all the routes(controllers and respective actions). I want a route to work only if it is listed in that record(yml file).
I have heard that it is possible to manage the resources by creating a yml file, though being new to rails I am not sure how to do it.
Suggestions would be highly appreciated.
I think I need to be more explicit about the query I have.
Agreed that we need to list all the GET,POST PUT AND DELETE requests in route in order to redirect a call.
What I am looking for is another YML file which will have the contollers and respective actions listed. The actions listed here should only be allowed to be routed and not others present in the route.rb.
Example :
I have the following route:
GET "fetch_ids" => "get_id#select"
Now if "get_id#select" is listed in my YML only then a route would be allowed.
How can I set this up?
It already works like that. No matter if you create a controller or an action, the controller and the action will be accessible only if they are somehow listed in the routes.rb file.
You can have 10 controllers, but just one in the routes.rb. The other 9 will not be reachable.
To list all the routes simply run
$ rake routes
To have a list of all routes that available, please try this Rack app (part of config/routes.rb)
match "/secret_routes" => proc { |env| [ 200, {'Content-Type' => 'text/plain'}, [Application.routes.routes.collect{|i| i.path.spec.to_s}.join("\n")] ] }

What is the replacement for ActionController::Base.relative_url_root?

I am porting a 2.x rails app to rails3; we'll call it foo-app. Foo-app is one section of a larger rails app and lives at main_rails_app.com/foo-app. Previously we just set up the following in our foo-app production config to ensure that our foo-app routes worked properly:
ActionController::Base.relative_url_root = "/foo-app"
However, with rails3, I now get:
DEPRECATION WARNING: ActionController::Base.relative_url_root is ineffective. Please stop using it.
I have since changed the config entry to the following:
config.action_controller.relative_url_root = "/foo-app"
This mostly works in that all calls to external resources (javascript/css/images) will use /foo-app. However, none of my routes change appropriately, or put another way, foo-app root_path gives me '/' when I would expect '/foo-app'.
Two questions:
What is the replacement for ActionController::Base.relative_url_root
if it is config.action_controller.relative_url_root, then why are my routes not reflecting the relative_url_root value I set?
You should be able to handle all that within the routes.rb file. Wrap all your current routes in scope; for instance.
scope "/context_root" do
resources :controller
resources :another_controller
match 'welcome/', :to => "welcome#index"
root :to => "welcome#index"
end
You can then verify your routing via the rake routes they should show your routes accordingly, including your context root(relative_url_root)
If you deploy via Passenger, use the RackBaseURI directive: http://www.modrails.com/documentation/Users%20guide%20Apache.html#RackBaseURI
Otherwise, you can wrap the run statement in your config.ru with the following block:
map ActionController::Base.config.relative_url_root || "/" do
run FooApp::Application
end
Then you only have to set the environment variable RAILS_RELATIVE_URL_ROOT to "/foo-app". This will even apply to routes set in gems or plugins.
Warning: do not mix these two solutions.
I feel like I must be over-complicating this and/or missing something, but this issue has been frustrating me for a while now, and here are my notes.
Summary
There are two separate issues with two points each for dynamic and static routes:
how to get routing to correctly match an incoming URL
for routes
for static files
how to generate URLs that include the relative_root
via url helpers
for static assets
One way to solve all four points:
Configure Nginx to strip the relative_root portion
This solves route matching; just write routes expecting URLs at / like development
Also static files are served as in development
Set RAILS_RELATIVE_URL_ROOT environment variable
This solves generated static asset helpers
Use the ScriptName middleware below (modify it to use the value from the environment)
This solves generated url helpers, e.g. users_path
Wrapping the Rails application in Rack::URLMap in config.ru (Christoph's answer)
# config.ru
map '/relative_root' do
run Myapp::Application
end
requires incoming URL contain the relative_url_root (Nginx can be configured to remove or retain this; see below)
Rack appends the relative_url_root to the Rack env SCRIPT_NAME rack/urlmap.rb:62
Rails adds the current request's SCRIPT_NAME to url_for options metal/url_for.rb:41
Rails' url_for prepends the script name when generating paths routing/url_for.rb:133
So that covers URLs generated by the url helpers, e.g. given UserController, users_path will be prefixed by the relative url root.
Set SCRIPT_NAME in middleware
# config.ru
class ScriptName
def initialize(app, name)
#app = app
#name = name
end
def call(env)
env['SCRIPT_NAME'] += #name
#app.call(env)
end
end
use ScriptName, '/relative_root'
run Rails.application
Has same effect as above, but
Requires that incoming URL NOT contain the relative_url_root
Setting RAILS_RELATIVE_URL_ROOT
value is saved in app.config.relative_url_root configuration.rb:41
which in turn affects asset paths asset_url_helper.rb:137
but that's it as far as I see
notably does not affect url helpers
Setting config.action_controller.relative_url_root
?? May affect assets compilation?
Overrides RAILS_RELATIVE_URL_ROOT env var?
Explicitly defining all routes under /relative_root (rizzah's answer)
# config/routes.rb
Myapp::Application.routes.draw do
scope '/relative_root' do
...
end
end
Url helpers will generate correct urls
Incoming URL must contain the relative url root (sensitive to Nginx configuration, see below), else "no route matches" exceptions
URLs requesting static assets, e.g. /relative_root/images/logo.png will result in "no route matches" exceptions. This may not be an issue if nginx is serving static assets anyway.
Nginx config
Given a config like this:
upstream myapp {
server localhost:3000;
}
server {
...
location /relative_root {
proxy_pass http://myapp/;
}
}
Nginx will strip out the /relative_root, and the Rails app will not see it. If you need the Rails app so see it, one way is to change the proxy_pass line:
...
proxy_pass http://myapp/relative_root/;
...

Custom URLs in Rails of the form custom.site.com

I would like to have my users specify custom URL paths such that those paths are placed in front of my site's name, i.e. if I have a site called www.orion.com, I'd like a user to be able to create his own little home page at johnny.orion.com.
I have successfully managed to implement orion.com/johnny, which works implemented by adding map.connect ':path' at the end of my routes then making sure the path variable is present when needed.
How can I get johnny.orion.com to function?
First, you'll need to set up wildcard DNS - so that the subdomains actually resolve to somewhere.
Then, configure your virtual host to accept connections from these subdomains:
# If you're using Apache, something like:
ServerAlias *.orion.com
Then, you can use the subdomain-fu gem to handle your routes within Rails. Have a look at the associated Railscast for some good tips.
The syntax for the gem is something like this:
link_to 'Posts', post_path(#post, :subdomain => 'johnny')
johnny.orion.com/posts/4

Rails router: Marking path as static (public)

Is there any way (middleware, etc) to tell the rails router that any route beginning with /photos should be considered as static data and should only be served from the /public/photos folder?
What i mean is that if the resource is not found, a 404 should be returned directly, without loading all rails stack.
This is for my dev env (single threaded mongrel), I don't want to use a front-end server.
You can define a Rack::Middleware Rack::Static (http://rack.rubyforge.org/doc/classes/Rack/Static.html)
use Rack::Static, :urls => ["/photo"]

Resources