We can't change the server configuration files, so we need to do our redirections at the rails level.
I have no problem with path redirections to external sites, like:
match "/meow" => redirect("http://meow.com/")
The issue is with the subdomains. I need to redirect for example:
http://my.example.com => http://example.com
How can this be done using routes.rb?
According to #cfernandezlinux's amazing answer, here's the same in Rails 4/Ruby 2 syntax:
constraints subdomain: "meow" do
get "/" => redirect { |params| "http://www.externalurl.com" }
end
match in routes.rb is not allowed in Rails 4.0 anymore. You have to use explicitly get, post, etc.
hashrocket syntax (=>) is for old Ruby, now in Ruby 2.0 we use param: 'value' syntax
I ended up doing something like this:
constraints :subdomain => "meow" do
match "/" => redirect { |params| "http://www.externalurl.com" }
end
If you don't want to hard-code the URL (so, for example, you can test/use this locally), you could do:
constraints subdomain: 'subdomain_from' do
get '/' => redirect(subdomain: :new_subdomain, path: '')
end
So now subdomain_from.google.com will redirect to new_subdomain.google.com.
Related
I have this simple rack middleware written to rewrite my subdomain :
def call(env)
request = Rack::Request.new(env)
if request.host.starts_with?("something-something")
[301, { "Location" => request.url.gsub('something-something','site-i-want') }, self]
else
#app.call(env)
end
And this works fine on development. But in production I get an error calling .each for TheNameOfMyRackMiddleware
Is there something that looks strangely syntactically incorrect about how I'm writing this?
I want this someting-something.mywebsite.com to go to site-i-want.mywebsite.com
I also tried it directly with my routes with this :
constraints :subdomain => 'something-something' do
redirect { |p, req| req.url.sub('something-something', 'site-i-want') }
end
Which works fine on development. But doesn't route before I get my failure saying that the site does not exist.
Entirely open to anyway of getting this accomplished.
How about trying this in your routes:
constraints subdomain: 'something-something' do
get ':any', to: redirect(subdomain: 'site-i-want', path: '/%{any}'), any: /.*/
end
It basically catches any request to the 'something-something' domain, and rewrites it with the existing path, but new subdomain.
I am trying to get rails to go to different controller#action according to the subdomain, and this is what I have so far in routes.rb
Petworkslabs::Application.routes.draw do
get '/', to: 'custom#show', constraints: {subdomain: '/.+/'}, as: 'custom_root'
get '/', to: "welcome#home", as: 'default_root'
end
rake shows the correct routes I want it to take
rake routes
Prefix Verb URI Pattern Controller#Action
custom_root GET / custom#show {:subdomain=>"/.+/"}
default_root GET / welcome#home
But for some reason, I can't get requests like abc.localhost:3000 to hit the custom controller. It always routes it to welcome#home. Any ideas? I am fairly new to rails, so any tips about general debugging would also be appreciated.
EDIT: I stepped through the code using the debugger and this is what I found
(rdb:32) request.domain
"abc.localhost"
(rdb:32) request.subdomain
""
(rdb:32) request.subdomain.present?
false
Looks like for some reason rails thinks that the subdomain is not present, even though its there. I wonder if its because I am doing this localhost.
Updated Answer:
Worked for me on Rails 3 & 4:
get '/' => 'custom#show', :constraints => { :subdomain => /.+/ }
root :to => "welcome#home"
#manishie's answer is right, but you'll still likely have issues in your devo environment if you're using localhost. To fix it add the following line to config/environments/development.rb:
config.action_dispatch.tld_length = 0
and then use #manishie's answer in routes.rb:
get '/' => 'custom#show', :constraints => { :subdomain => /.+/ }
root :to => "welcome#home"
The issue is that tld_length defaults to 1 and there's no domain extension when you're using localhost so rails fails to pickup the subdomain. pixeltrix explains it really well here: https://github.com/rails/rails/issues/12438
For some reason request.subdomain was not getting populated at all (I suspect this is because I have doing this on localhost, I have opened a bug here https://github.com/rails/rails/issues/12438). This was causing the regex match in routes.rb to fail. I ended up creating a custom matches? method for Subdomain which looks something like this
class Subdomain
def self.matches?(request)
request.domain.split('.').size>1 && request.subdomain != "www"
end
end
and hooking that up in routes.rb
constraints(Subdomain) do
get '/', to: "custom#home", as: 'custom_root'
end
this seems to work.
EDIT: More information in the github issues page https://github.com/rails/rails/issues/12438
I am developing a site that mixes http and https a lot - whats the best/easiest way to make the links use the right protocol for the route - can it be specified in the routes file?
Say I have the following route in Rails 3.
match "/test" => "test#index", :as => :test, :constraints => { :protocol => 'https' }
If I'm on a http page, and I use test_url(), it'll output http://domain.com/test. I want https://domain.com/test instead.
I know I can use test_url(:secure => true), but that's duplicating logic.
I know I could have http://domain.com/test to https://domain.com/test, but that's an extra redirect, plus it fails on form posts.
Ideas?
Use test_url(:protocol => 'https') for https urls.
Haven't tried but add this in your ApplicationController:
def default_url_options(options={})
{ :secure => true }
end
def default_url_options(options={})
{ :protocol => "https" }
end
For Rails 3.2 I used a combination of #apneadiving's answer. Adding the below code to my ApplicationController
def default_url_options(options={})
options.merge{ :protocol => "https" }
end
It looks like this will be solved in Rails 4! https://github.com/rails/rails/commit/9b4514c3b8ecfbc40a44dbd4c2ebd4ce67f4a459
Rails 3 SSL routing redirects from https to http answers this question pretty well. In short, there's not a great way to do it. I submitted the following Rails bug: https://github.com/rails/rails/issues/3571
To generate https url, add an option called protocol with value https
test_url(protocol: 'https')
You can use a plugin called ss_requirement, it will provide you with methods like
ssl_required
ssl_allowed
You can simply add this in your controller to enable ot disable https on any action
ssl_allowed :login, :update_profile
https://github.com/rails/ssl_requirement
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
Please note:
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.
Goal
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.
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
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
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
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.
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\./ }
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
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.
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
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:
https://github.com/cwninja/rack-force_domain
https://github.com/tylerhunt/rack-canonical-host
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).
I'm trying to create a routing situation where by default, any URL's such as this:
/foo
/something
/foo.php
/somethingelse.xml
/something.something.else
etc.
will all route to one controller, assuming they don't route anywhere else.
i can get this to work with the following code in my routes:
map.myroute '/:file_or_folder', :controller => 'mycontroller'
this works fine as long as there are no dots in the URL:
/something
but this wont work:
/something.foo
any ideas?
Dots are not allowed by default. You can specify a regex for what file_or_folder can match, such as this:
map.myroute '/:file_or_folder', :controller => 'mycontroller', :file_or_folder => /.*/