Reputation: 77778
I understand there are a lot of questions that answer this. I'm familiar with .htaccess
and nginx.conf
methods, but I do not have access to such traditional configuration methods on Heroku.
Simone Carletti gave this answer that leverages Rails 2.x Metals, but I'm using Rails 3 and this isn't compatible:
Redirect non-www requests to www URLs in Ruby on Rails
I'm not looking for a simple before_filter
in my ApplicationController. I'd like to accomplish a rewrite similar to Simone's. I believe this is job for the webserver or middleware like Rack at the very least, so I'd like to leave this bit out of the actual application code.
redirect to status
----------------------------------------------------
www.foo.com foo.com 301
www.foo.com/whatever foo.com/whatever 301
Only hosts matching /^www\./
should be redirected. All other requests should be ignored.
Upvotes: 36
Views: 13269
Reputation: 610
In Ruby on Rails 4, removing www. from any URL whilst maintaining the pathname can be achieved simply by using:
# config/routes.rb
constraints subdomain: 'www' do
get ':any', to: redirect(subdomain: nil, path: '/%{any}'), any: /.*/
end
In contrast, adding www. to the beginning of any URL that doesn't already have it can be achieved by:
# config/routes.rb
constraints subdomain: false do
get ':any', to: redirect(subdomain: 'www', path: '/%{any}'), any: /.*/
end
Upvotes: 51
Reputation: 11289
In Rails 3
#config/routes.rb
Example::Application.routes.draw do
constraints(:host => "www.example.net") do
match "(*x)" => redirect { |params, request|
URI.parse(request.url).tap { |x| x.host = "example.net" }.to_s
}
end
# ....
# .. more routes ..
# ....
end
Upvotes: 6
Reputation: 6749
For Rails 4 the above solutions have to be appended with the Verb construction e.g. via: [:get, :post]
. Duke's solution becomes:
constraints(:host => /^www\./) do
match "(*x)" => redirect { |params, request|
URI.parse(request.url).tap {|url| url.host.sub!('www.', '') }.to_s
}, via: [:get, :post]
end
Upvotes: 3
Reputation: 613
Nothing wrong with the approaches above, but there are also a couple of gems that provide Rack middleware to do this.
I like the way that they keep this behaviour separate from the app itself, but it's not a particularly strong argument either way. I also use middleware to do this when working with Sinatra, so prefer to use a technique that I can use on apps built from Rails and/or Sinatra (I often run Nesta embedded in Rails).
Anyway, here they are:
The first is simpler (and the one I've been using) while the second offers a couple more features (that I'm yet to need, but appreciate).
Upvotes: 2
Reputation: 7995
If you want to redirect from the top-level domain (TLD) to the www subdomain, use this code:
constraints :subdomain => '' do
match '(*any)' => redirect { |p, req| req.url.sub('//', '//www.') }
end
Note: This code the use of sub, not gsub, because sub replaces the first occurrence of the double-slashes where gsub would replace all double-slashes.
Upvotes: 3
Reputation: 1766
A one-line version of Duke's solution. Just add to the top of routes.rb
match '(*any)' => redirect { |p, req| req.url.sub('www.', '') }, :constraints => { :host => /^www\./ }
Upvotes: 7
Reputation: 7444
I really like using the Rails Router for such things. Previous answers were good, but I wanted something general purpose I can use for any url that starts with "www".
I think this is a good solution:
constraints(:host => /^www\./) do
match "(*x)" => redirect { |params, request|
URI.parse(request.url).tap {|url| url.host.sub!('www.', '') }.to_s
}
end
Upvotes: 12
Reputation: 597
There's a better approach if you're using Rails 3. Just take advantage of the routing awesomeness.
Foo::Application.routes.draw do
constraints(:host => /^example.com/) do
root :to => redirect("http://www.example.com")
match '/*path', :to => redirect {|params| "http://www.example.com/#{params[:path]}"}
end
end
Upvotes: 13
Reputation: 786
Take a look at this middleware, it should do precisely what you want:
http://github.com/iSabanin/www_ditcher
Let me know if that worked for you.
Upvotes: 7