Goodbye .htaccess, Hello Rails

Apache, Rails Posted on

Remember the good old days of PHP? Mastering a redirect was nearly impossible without complicated PHP code or writing a server instruction (.htaccess). Let's take a minute to examine the past and present, and then compare and contrast some of the advantages and disadvantages of each.

Pre-Rails

Before Rails, redirects were done primarily server-side or via complicated application logic. For example, in PHP, one would do something like the following:

<?php
  define('APP_DOMAIN', 'https://example.com');

  if($_SERVER['HTTP_HOST'] != APP_DOMAIN) {
    header('HTTP/1.1 301 Moved Permanently');
    header('Location: ' + APP_DOMAIN);
  }
?>

Then, we'd need to include this in every file:

<?php require('ensure_domain.php') ?>

Well, this soon became cumbersome to add to every file, so we decided to just let the server handle it. This was most often accomplished via a .htaccess file:

Options +FollowSymLinks
RewriteEngine on
RewriteCond %{HTTP_HOST} [^example\.com]
RewriteRule ^(.*)$ <a href="https://www.example.com/%241">https://www.example.com/$1</a> [R=301,L]

Not only is this difficult to read, but this file was automatically hidden in Unix-based systems (because it's prefixed with a dot ["."]). It was often missed under source control because developers simply forgot to include it. Furthermore, it creates a very tight tie between the application and the server. Finally, not all hosting providers actually allowed modifying the web server configuration, at which point you were stuck.

Rails

The Rails framework makes it very easy to ensure a domain. Understanding that, by default, all requests go through the application_controller.rb allows us to write our ensure domain code once:

class ApplicationController &lt; ActionController::Base
  protect_from_forgery

  APP_DOMAIN = 'www.example.com'
  before_filter :ensure_domain

  def ensure_domain
    unless request.env['HTTP_HOST'] == APP_DOMAIN || Rails.env.development?
      redirect_to "https://#{APP_DOMAIN}", :status =&gt; 301
    end
  end
end

We simply define a constant and they quickly ask Rails if the HTTP_HOST == APP_DOMAIN. If it doesn't, we redirect with a 301. NOTE: We don't want to redirect on development - hence the || Rails.env.development?

Advantages

  • Rails approach is much easier to read and much cleaner
  • Rails approach is easily checked into version control
  • Rails approach is easily flexible
  • Rails approach is server-independent

Disadvantages

  • Rails is slow - the request needs to travel all the way up the stack
  • Rails server needs to restart after a change

What do you think?

About Seth

Seth Vargo is an engineer at Google. Previously he worked at HashiCorp, Chef Software, CustomInk, and some Pittsburgh-based startups. He is the author of Learning Chef and is passionate about reducing inequality in technology. When he is not writing, working on open source, teaching, or speaking at conferences, Seth advises non-profits.