27

Using Morph Labs' Appspace to deploy a site means no automated way to redirect 'myapp.com' to 'www.myapp.com' (and no access to .htacess).

Is there an in-rails way to do this? Would I need a plugin like subdomain-fu?

More specifically, I'm trying to do something like:

  • 'myapp.com' => 'www.myapp.com'
  • 'myapp.com/session/new' => 'www.myapp.com/session/new'

Basically, I always want the 'www' subdomain prepended on every request (because the SSL cert specifically has a common name of 'www.myapp.com').

JJJ
  • 32,902
  • 20
  • 89
  • 102
Allan L.
  • 396
  • 3
  • 10

7 Answers7

30

Maybe something like this would do the trick:

class ApplicationController < ActionController::Base
  before_filter :check_uri

  def check_uri
    redirect_to request.protocol + "www." + request.host_with_port + request.request_uri if !/^www/.match(request.host)
  end
end
carson
  • 5,751
  • 3
  • 24
  • 25
  • Looks sweet, I'm gonna give this a try on the next deploy and report back on the results! – Allan L. Nov 29 '08 at 04:16
  • Carson, I apologize for not marking your answer as the answer I accepted previously. I didn't realize all I had to do was click on the check mark. Again, my apologies. – Allan L. Jan 05 '09 at 12:34
  • 2
    This is a great use case for a Rack middleware though. You can get some ideas from this one: http://coderack.org/users/jtrupiano/entries/37-rackrewrite – hgmnz Nov 13 '09 at 15:37
  • 1
    MAKE SURE TO PUT THE CHECK_URI AS THE FIRST BEFORE FILTER. I have recently run into several very difficult problem to track down in my app, and they all resulted from logged_in checks occuring before the check_uri call. – Mike H Nov 18 '09 at 16:19
  • hgimenez is absolutely correct that a rack middleware is perfect for this situation. The link he gives returns a 404 now, but the same site has a middleware called "Force Domain" that likely replaced initial middleware hgimenez linked to. – Scott Swezey Jun 28 '10 at 20:39
  • This is great code but if it's SSL this doesn't prevent the SSL browser warning from appearing. – AnApprentice Dec 01 '10 at 21:40
  • This doesn't work in Rails 3.2 or 4. You'll need to change `request.request_uri` to `request.fullpath` – Dex Jul 28 '13 at 08:15
8

Carson's answer works great.

Here's the code to go the other way (www -> no www)

before_filter :check_uri

def check_uri
  if /^www/.match(request.host)
    redirect_to request.protocol + request.host_with_port[4..-1] + request.request_uri 
  end
end
Mike H
  • 509
  • 3
  • 2
5

I had to change Carson's answer to get this to work in Rails 3. I replaced request.uri with request.fullpath:

class ApplicationController < ActionController::Base
  protect_from_forgery

  Rails.env.production? do
    before_filter :check_url
  end

  def check_url
    redirect_to request.protocol + "www." + request.host_with_port + request.fullpath if !/^www/.match(request.host)
  end
end
Lee McAlilly
  • 9,084
  • 12
  • 60
  • 94
2

This worked great for me. I did make one small addition as I only wanted this behavior in my production environment:

def check_uri
  redirect_to request.protocol + "www." + request.host_with_port + request.request_uri if !/^www/.match(request.host) if Rails.env == 'production'
end
Levi Rosol
  • 4,398
  • 6
  • 28
  • 36
1

I know this is answered, but I thought everyone else should know about the CodeRack: Canonical Host solution. This is really nice as it allows for env specific redirects. http://coderack.org/users/tylerhunt/middlewares/6-canonical-host

erskingardner
  • 2,198
  • 1
  • 20
  • 24
0

For those of you who are looking to also force SSL using heroku, this worked well for me, based on Heroku SSL on root domain

In my DNS settings I set up a URL / Forward record (DNS Simple)

URL foo.com     3600        http://www.foo.com

The CNAME setup only needs to be setup for WWW

CNAME   www.foo.com 3600        providedssslendpoint.herokussl.com

I also had to setup and Alias for my root

ALIAS   foo.com 3600        providedsslendpoint.herokussl.com

Then I decided to simply replace foo.com with an env variable ENV['SITE_HOST'] (where SITE_HOST might equal www.foo.com or test.foo.com) so I can have control via my heroku configuration. That way, I can control what happens in different environments. (for setting up env variables locally see https://github.com/bkeepers/dotenv)

For example, my test app uses test.foo.com as the url it also has its own SSL endpoint so that works fine for me.

  before_filter :check_domain

  def check_domain
    if Rails.env.production? || Rails.env.testing? and request.host.downcase != ENV['SITE_HOST']
      redirect_to request.protocol + ENV['SITE_HOST'] + request.fullpath, :status => 301
    end
  end

From now on, end users will always access www with forced SSL. Old links will suffer a small hang but nothing noticeable.

Community
  • 1
  • 1
0

Here is a couple of different ways:

 head :moved_permanently, :location => ‘http://www.newdomain.com’

another:

def rails_301
headers["Status"] = "301 Moved Permanently"
redirect_to "http://www.newdomain.com"
end 
Stepan Mazurov
  • 1,354
  • 10
  • 15
  • I just edited my original question to give more detail on what I'm trying to accomplish. Does your answer still apply? – Allan L. Nov 29 '08 at 03:50