github
Advanced Search
  • Home
  • Pricing and Signup
  • Explore GitHub
  • Blog
  • Login

jtrupiano / rack-rewrite

  • Admin
  • Watch Unwatch
  • Fork
  • Your Fork
  • Pull Request
  • Download Source
    • 79
    • 6
  • Source
  • Commits
  • Network (6)
  • Issues (1)
  • Downloads (6)
  • Wiki (1)
  • Graphs
  • Branch: master

click here to add a description

click here to add a homepage

  • Branches (1)
    • master ✓
  • Tags (6)
    • v0.2.1
    • v0.2.0
    • v0.1.3
    • v0.1.2
    • v0.1.1
    • v0.1.0
Sending Request…
Enable Donations

Pledgie Donations

Once activated, we'll place the following badge in your repository's detail box:
Pledgie_example
This service is courtesy of Pledgie.

A web server agnostic rack middleware for defining and applying rewrite rules. In many cases you can get away with Rack::Rewrite instead of writing Apache mod_rewrite rules. — Read more

  cancel

http://github.com/jtrupiano/rack-rewrite

  cancel
  • Private
  • Read-Only
  • HTTP Read-Only

This URL has Read+Write access

Regenerated gemspec for version 0.2.1 
jtrupiano (author)
Wed Jan 06 14:42:41 -0800 2010
commit  381df8ca7e729a32238a95239d239f08a1aa1643
tree    c2ba6c11030e143acb081ae2ed7073a554046b09
parent  127fde391b9a65256b499002e243d8b0e81b49ab
rack-rewrite / README.rdoc README.rdoc
100644 196 lines (141 sloc) 7.65 kb
edit raw blame history

rack-rewrite

A rack middleware for defining and applying rewrite rules. In many cases you can get away with rack-rewrite instead of writing Apache mod_rewrite rules.

References

  • Source
  • Documentation
  • Rack::Rewrite for Site Maintenance and Downtime
  • Rack::Rewrite + Google Analytics Makes Site Transitions Seamless

Usage

Sample rackup file

  gem 'rack-rewrite', '~> 0.2.1'
  require 'rack-rewrite
  use Rack::Rewrite do
    rewrite '/wiki/John_Trupiano', '/john'
    r301 '/wiki/Yair_Flicker', '/yair'
    r302 '/wiki/Greg_Jastrab', '/greg'
    r301 %r{/wiki/(\w+)_\w+}, '/$1'
  end

Sample usage in a rails app

  config.gem 'rack-rewrite', '~> 0.2.1'
  require 'rack-rewrite
  config.middleware.insert_before(Rack::Lock, Rack::Rewrite) do
    rewrite '/wiki/John_Trupiano', '/john'
    r301 '/wiki/Yair_Flicker', '/yair'
    r302 '/wiki/Greg_Jastrab', '/greg'
    r301 %r{/wiki/(\w+)_\w+}, '/$1'
  end

Use Cases

Rebuild of existing site in a new technology

It’s very common for sites built in older technologies to be rebuilt with the latest and greatest. Let’s consider a site that has already established quite a bit of "google juice." When we launch the new site, we don’t want to lose that hard-earned reputation. By writing rewrite rules that issue 301’s for old URL’s, we can "transfer" that google ranking to the new site. An example rule might look like:

  r301 '/contact-us.php', '/contact-us'
  r301 '/wiki/John_Trupiano', '/john'

Retiring old routes

As a web application evolves you will undoubtedly reach a point where you need to change the name of something (a model, e.g.). This name change will typically require a similar change to your routing. The danger here is that any URL’s previously generated (in a transactional email for instance) will have the URL hard-coded. In order for your rails app to continue to serve this URL, you’ll need to add an extra entry to your routes file. Alternatively, you could use rack-rewrite to redirect or pass through requests to these routes and keep your routes.rb clean.

  rewrite %r{/features(.*)}, '/facial_features$1'

CNAME alternative

In the event that you do not control your DNS, you can leverage Rack::Rewrite to redirect to a canonical domain. In the following rule we utilize the $& substitution operator to capture the entire request URI.

  r301 %r{.*}, 'http://mynewdomain.com$&', :if => Proc.new {|rack_env|
    rack_env['SERVER_NAME'] != 'mynewdomain.com'
  }

Site Maintenance

Most capistrano users will be familiar with the following Apache rewrite rules:

  RewriteCond %{REQUEST_URI} !\.(css|jpg|png)$
  RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f
  RewriteCond %{SCRIPT_FILENAME} !maintenance.html
  RewriteRule ^.*$ /system/maintenance.html [L]

This rewrite rule says to render a maintenance page for all non-asset requests if the maintenance file exists. In capistrano, you can quickly upload a maintenance file using:

  cap deploy:web:disable REASON=upgrade UNTIL=12:30PM

We can replace the mod_rewrite rules with the following Rack::Rewrite rule:

  maintenance_file = File.join(RAILS_ROOT, 'public', 'system', 'maintenance.html')
  send_file /.*/, maintenance_file, :if => Proc.new { |rack_env|
    File.exists?(maintenance_file) && rack_env['REQUEST_URI'] !~ /\.(css|jpg|png)/
  }

If you’re running Ruby 1.9, this rule is simplified:

  maintenance_file = File.join(RAILS_ROOT, 'public', 'system', 'maintenance.html')
  send_file /(.*)$(?<!css|png|jpg)/, maintenance_file, :if => Proc.new { |rack_env|
    File.exists?(maintenance_file)
  }

For those using the oniguruma gem with their ruby 1.8 installation, you can get away with:

  maintenance_file = File.join(RAILS_ROOT, 'public', 'system', 'maintenance.html')
  send_file Oniguruma::ORegexp.new("(.*)$(?<!css|png|jpg)"), maintenance_file, :if => Proc.new { |rack_env|
    File.exists?(maintenance_file)
  }

Rewrite Rules

:rewrite

Calls to #rewrite will simply update the PATH_INFO and REQUEST_URI HTTP header values and pass the request onto the next chain in the Rack stack. The URL that a user’s browser will show will not be changed. See these examples:

  rewrite '/wiki/John_Trupiano', '/john'   # [1]
  rewrite %r{/wiki/(\w+)_\w+}, '/$1'       # [2]

For [1], the user’s browser will continue to display /wiki/John_Trupiano, but the actual HTTP header values for PATH_INFO and REQUEST_URI in the request will be changed to /john for subsequent nodes in the Rack stack. Rails reads these headers to determine which routes will match.

Rule [2] showcases the use of regular expressions and substitutions. [2] is a generalized version of [1] that will match any /wiki/FirstName_LastName URL’s and rewrite them as the first name only. This is an actual catch-all rule we applied when we rebuilt our website in September 2009 ( www.smartlogicsolutions.com ).

:r301, :302

Calls to #r301 and #r302 have the same signature as #rewrite. The difference, however, is that these actually short-circuit the rack stack and send back 301’s and 302’s, respectively. See these examples:

  r301 '/wiki/John_Trupiano', '/john'                # [1]
  r301 '/wiki/(.*)', 'http://www.google.com/?q=$1'   # [2]

Recall that rules are interpreted from top to bottom. So you can install "default" rewrite rules if you like. [2] is a sample default rule that will redirect all other requests to the wiki to a google search.

:send_file, :x_send_file

Calls to #send_file and #x_send_file also have the same signature as #rewrite. If the rule matches, the ‘to’ parameter is interpreted as a path to a file to be rendered instead of passing the application call up the rack stack.

  send_file /*/, 'public/spammers.htm', :if => Proc.new { |rack_env|
    rack_env['HTTP_REFERER'] =~ 'spammers.com'
  }
  x_send_file /^blog\/.*/, 'public/blog_offline.htm', :if => Proc.new { |rack_env|
    File.exists?('public/blog_offline.htm')
  }

Tips

Keeping your querystring

When rewriting a URL, you may want to keep your querystring in tact (for example if you’re tracking traffic sources). You will need to include a capture group and substitution pattern in your rewrite rule to achieve this.

  rewrite %r{/wiki/John_Trupiano(\?.*)?}, '/john$1'

This rule will store the querystring in a capture group (via ’(?.*)’ ) and will substitute the querystring back into the rewritten URL (via $1).

Rule Guards

All rules support passing guards as Procs/lambdas. Guards simply return true or false indicating whether the rule declaration is a match. The following example demonstrates how the presence of a maintenance page on the filesystem can be utilized to take your site(s) offline.

  maintenance_file = File.join(RAILS_ROOT, 'public', 'system', 'maintenance.html')
  x_send_file /.*/, maintenance_file, :if => Proc.new { |rack_env|
    File.exists?(maintenance_file)
  }

Arbitrary Rewriting

All rules support passing a Proc as the second argument allowing you to perform arbitrary rewrites. The following rule will rewrite all requests received between 12AM and 8AM to an unavailable page.

  rewrite %r{(.*)}, lambda { |match, rack_env|
    Time.now.hour < 8 ? "/unavailable.html" : match[1]
  }

Copyright

Copyright © 2009-2010 John Trupiano. See LICENSE for details.

Blog | Support | Training | Contact | API | Status | Twitter | Help | Security
© 2010 GitHub Inc. All rights reserved. | Terms of Service | Privacy Policy
Powered by the Dedicated Servers and
Cloud Computing of Rackspace Hosting®
Dedicated Server