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

匿名 (未验证) 提交于 2019-12-03 03:04:01

问题:

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:

  1. What is the replacement for ActionController::Base.relative_url_root
  2. if it is config.action_controller.relative_url_root, then why are my routes not reflecting the relative_url_root value I set?

回答1:

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)



回答2:

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.



回答3:

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:

  1. how to get routing to correctly match an incoming URL
    • for routes
    • for static files
  2. 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

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/; ...


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!