1

I need to be able to rewrite non www to www but NOT in the case when there is a (non www) subdomain present.

so example.com to-> www.example.com but sub.example.com remains sub.example.com

I'm in rails 3 and it seems this should be accomplished using Rack Middleware, but the snag is this is a multitenant app so the TLD could potentially be any domain.

This is where I am so far:

  Class Www

  def initialize(app)
    @app = app
  end

  def call(env)

    request = Rack::Request.new(env)

    if !request.host.starts_with?("www.")
      [301, {"Location" => request.url.sub("//","//www.")}, self]
    else
      @app.call(env)
    end

  end

  def each(&block)
  end

end

Any pointers would be appreciated....

cman77
  • 1,753
  • 1
  • 22
  • 48
  • Can you handle it in the web server instead of by rails or rack? Apache or Nginx etc. have the ability to do this. – Joel Friedlaender Sep 08 '12 at 04:16
  • I'm on Heroku so don't have access to that. – cman77 Sep 08 '12 at 11:45
  • I wouldn't have your website on heroku. Heroku is going to have downtime (even if small), and when your app is down, customers will go to your website to look for support. It's bad if both are down. Also you don't want to disrupt users of your app to update your website. I would put your website on something other service (ie. Linode), and point root domain and www to that service, then send all other *.subdomain.com requests to heroku. You can do that in your dns. Then use nginx or whatever on your website server for the redirect. – Joel Friedlaender Sep 09 '12 at 02:05
  • This also lets you separate the code for your website and app in case you want to let someone work on your website without getting the code for your app. I dont know why my answer was converted to a comment either... it was an answer to solve the OPs problem, even if not directly answering the question as stated. – Joel Friedlaender Sep 09 '12 at 02:06

1 Answers1

1

The code you have right now will rewrite "sub.example.com", your call function could be rewritten like this :

def call(env)
  request = Rack::Request.new(env)

  # Redirect only if the host is a naked TLD
  if request.host =~ /^[^.]+\.[^.]+$/
    [301, {"Location" => request.url.sub("//","//www.")}, self]
  else
    @app.call(env)
  end
end
Benoit Garret
  • 14,027
  • 4
  • 59
  • 64
  • thanks - this exactly answered the question. I had come up with another solution which is not as clean as the regex:
    `def needs_www?(request) url_array = request.host.split(".") %w{dev com net co}.any? {|tld| tld==url_array[1]} end`
    – cman77 Sep 09 '12 at 16:24
  • ugh - sorry struggling w/ this infuriating commenting markup...anyways - I basically split on the "." and checked for it's location in the ensuing array - which worked - but is not as elegant as the regex - so thank you! – cman77 Sep 09 '12 at 16:31
  • @cman77 I should mention, my solution will break with composed TLDs (eg. `.co.uk`). If you need to handle those cases, using something like the [public suffix library](http://www.simonecarletti.com/blog/2010/06/public-suffix-list-library-for-ruby/) should be the easiest way. – Benoit Garret Sep 09 '12 at 17:30