Camping / Rackで、アプリのベースURLを取得するにはどうすればよいですか?送信するメールに入れられるように知りたいです。
(開発中)かもしれません
また
http://localhost:9292
また
http://localhost:80/game
または本番環境で
http://fancy-snake.heroku.com
これまでのところ私は
url = @env['rack.url_scheme'] + "://" + @env['HTTP_HOST'] + R(LoginX, u.secret)
これは、最初と3番目のケースで機能するようです。アプリがlocalhost/prefix
You have to be a little careful with this, as there are a some subtle potential traps. The Rack::Request
class will probably be helpful here.
First, you can’t really get the url for the app, as it may be responding to multiple urls (via Rack routes, Apache config, etc), so you’re looking at getting the url for the particular request. If you’re only serving requests from one url this won’t matter.
The scheme for the request is in the env
hash under the rack.url_scheme
, but this is only for the “last leg” of the request. If your app is behind a proxy of some sort (Nqinx, Apache etc.) then you want to get the scheme of the real request, not the request from the proxy to the machine your app is running on. If you’ve configured your proxy correctly it should be setting a header so you can tell what the original scheme was. Rack::Request
has a scheme
method that takes these headers into account.
The host for the url is probably in the env
hash under the HTTP_HOST
key, but this header is not necessarily present (admittedly that’s pretty unlikey nowadays). You should fall back on SERVER_NAME
and SERVER_PORT
. Additionally there’s the issue of handling proxied requests, you want the hostname of the original request, not the backend server. Again, Rack::Request
provides host_with_port
and host
methods that deal with these issues.
Rack::Request
also provides a base_url
method that combines scheme and host, and additionally only includes the port if differs from the default (80 or 443).
The location that your app is mounted is in the env
hash under the SCRIPT_NAME
key. This would be /game
in your second example, and can be empty if your app mounted at the root of your server. Again, Rack::Request
provides a script_name
method, although this one simply returns the value of the entry in the env
hash.
So, in summary, you probably want to use something like this:
req = Rack::Request.new env
url = req.base_url + req.script_name
which looks pretty simple, but is taking care of various possibilities for you.
Additionally, you miight find the the Rack specification useful to have a read of, it contains details of the various entries that should be in the env
hash.
Camping has a helper called URL
which returns the absolute URL to your app:
URL() # => #<URL:http://test.ing/blog/>
URL() + "view/12" # => #<URL:http://test.ing/blog/view/12>
URL("/view/12") # => #<URL:http://test.ing/blog/view/12>