[Rails] Avoid parsing URL in Apache conf?

Marten Veldthuis marten at standardbehaviour.com
Sat Nov 20 20:10:25 GMT 2004


David Heinemeier Hansson wrote:
> We are. It was one of the first wishes to make it on the list:
> http://www.rubyonrails.org/show/DispatcherRewritingWish

I've discussed an approach with David shortly on IRC, and promised to 
put up a full example. So here it is:

# Suggestion for a Rails Rewriting Engine.
# By Marten Veldthuis, 20041120

def rewrite
   # Given a raw url /path/to/somewhere, url.<name> compares from the
   # start of the currently remaining url (less a "/" prefix if it
   # exists), and if it matches:
   #
   #   * it sets @params[<name>] to the matched string unless the second
   #     argument +dont_set_param+ to the call url.<name> is +true+.
   #     Second argument defaults to false.
   #   * removes the matched string from the remaining url
   #   * executes the given block, passing the MatchData

   url.section_name(/([-_a-zA-Z0-9]+)/) do |match|
     # (match contains an instance of MatchData)

     # In this case, my requirement is to match a given section name
     # to it's type. For instance, some section may be called "weblog"
     # and be of the "journal" type, but another could be "see-also",
     # and of the "links" type. So to find out what controller to use
     # I must either pre-define all possible names and their types
     # (which is what I do now by writing a .htaccess automatically),
     # or I could look up the section here.
     #
     # I can fully understand if David finds this too smelly to allow it
     # in Rails.

     # @active_section would be passed into the controller#action (and
     # later the view) just like passing instance vars from action to
     # view.
     @active_section = Section.find_by_name(match[0])

     # This sets what controller to use. Eg. <tt>vendor_journal</tt> or
     # <tt>vendor_links</tt>. Action
     @controller = "vendor_" + @active_section.type
     @action = "index"

     url.year(/\d{4}/) do
       # If a year is given, we want to display the archive instead. So,
       # we override the action.
       @action = "archive_year"

       url.month(/\d{1,2}/) do
	@action = "archive_month"
	
	url.day(/\d{1,2}/) do
	  @action = "archive_day"

	  url.entry_name(/([-_a-zA-Z0-9]+)/) do
	    @action = "archive_entry"
	  end
	end
       end
     end
   end

   # This is reachable only if the outmost match (url.section_name)
   # failed. Ofcourse, the same applies to any url.<name> call.

   url.admin(/admin/, false) do
     url.section(/sections\/([-_a-zA-Z0-9]+)/, false) do |match|
       @params["section_name"] = match[0]
       @active_section = Section.find_by_name(match[0])

       # Notice how I'm ending this without having set a controller
       # anywhere. If by the end no controller or action has been set,
       # autodetection is attempted at the remaining url, following the
       # normal basic rules. If it fails, a HTTP 404 would occur.
     end
   end

   # Equivalent for the default rewriting rules
   @controller = "weblog"
   @action = "index"

   # No match has ever been made. At this point autodetection is started
   # trying to fill in the controller, action and id. If the url is
   # blank, the defaults from above are used, otherwise if it fails a 404
   # occurs. If it's successful in detecting at least a controller
   # (action would default to "index") obviously the controller is
   # called.
end

Comments?

-- 
Marten Veldthuis


More information about the Rails mailing list