Ruby on Rails
HowtoMakeCustomRewriteRules

WikiGardening in progress. We’re combining/reorganizing several related howto’s at the moment, apologies for the dust. Since Rails 0.10 includes Routes, that are meant to replace the use of mod_rewrite and provide more portability across web servers, much of this information is nolonger relevant; the remander is being moved under HowToSetTheBaseURLsOfYourRailsApps.

Purpose

I’m writing your typical groupware/community web app, which has a number of groups, each of which has a few apps, like a bboard, calendar, files, etc.

I want URLs of the form:

/groups/123/bboard/show/234

Or in general form:

/groups/group_id/controller/action/id

Just like with Rails’ default rules, you can leave off ID. If you leave out both ID and action, the action will default to index.

The rules

I modified my public/.htaccess file, adding the following lines:

RewriteRule ^groups/([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)/$ /dispatch.cgi?group_id=$1&controller=$2&action=index [QSA] [L]
RewriteRule ^groups/([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)$ /dispatch.cgi?group_id=$1&controller=$2&action=$3 [QSA] [L]
RewriteRule ^groups/([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)$ /dispatch.cgi?group_id=$1&controller=$2&action=$3&id=$4 [QSA] [L]

The first one deals with the case with no action or ID. The second is the one with action, but no ID. And the third has both. They all have group_id in the path.

Capturing the group_id

Now these URLs will invoke the controller and action correctly, and you can get the group_id by saying @params["group_id"].

However, since you’re going to be using the group_id all over the place, David suggested a somewhat more clever solution: Put it as a filter in your abstract ApplicationController. Here’s how:

...
before_filter :findings
...
private 
  def findings
    @group = Group.find(@params["group_id"]) if @params["group_id"]
  end
...

This will setup an instance variable @group with the group model object for the group you’re in, if group_id was found in the parameters. If not, @group will be undefined.

Generating links

The only remaining part is generating the links that will take you there.

Once you’re “inside” a group, so to speak, things are easy. Saying

url_for :action => "new"

will give you the URL for the new action within the current controller, with the /groups/123/ part of the URL intact.

It works the same if you’re switching to another controller within the group.

To get from outside the group (e.g. the login page or the My Groups page or whatever it’s called) into a group, use this:

url_for :controller_prefix => "groups/#{group.id}", :controller => "bboard"

The controller_prefix is the trick that bumps you into the group URL space, so to speak.

Similarly, to get out of the group URL space, you can either just hard-code the URL, or you can be fancy about it and pass in an empty controller_prefix, like this:

url_for :controller_prefix => "", :controller => "login", :action => "logout"

Resources



Question: How would one go about making this example more dynamic? ie, having /groupname/ as a prefix, so following the above example the url would be something like /groupname/bboard/show/234
- jsdk

As a start (keeping the above examples in mind):
in the controller that would redirect

usergroup = Group.find(@session["user"].group_id) 
# redirect to /_usersgroupname_/foo
redirect_to :controller_prefix => usergroup.name, :controller => "foo"

and in out .htaccess file

RewriteRule ^([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)/$ /dispatch.cgi?group_name=$1&controller=$2&action=index [QSA] [L]
<a href="http://wiki.rubyonrails.com/rails/pages/RewriteRule" class="existingWikiWord">RewriteRule</a> ^([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)$ /dispatch.cgi?group_name=$1&controller=$2&action=$3 [QSA] [L]
<a href="http://wiki.rubyonrails.com/rails/pages/RewriteRule" class="existingWikiWord">RewriteRule</a> ^([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)$ /dispatch.cgi?group_name=$1&controller=$2&action=$3&id=$4 [QSA] [L]

Question When developing with webrick servlet, how do I do something similar?

However, this particular code/rewriterule isn’t perfect yet, how to improve?
- jsdk

category:Howto