TechnoMage

Software Wizardry - Quality, Service, Experience

Technomage Blog

Merb Routing 1

The Merb routing approach is a real god-send, and cool to boot. Rather than routing against a fixed set of parameters as in Rails, you route against any method result from the request object. This makes the public API for routing totally extensible and flexible.

In my case I want to route based on the domain name of the requested host. This allows me to serve different content for different domains with the same application. This would apply to private domains for a tenanted application, or to an app serving many domains such as a CMS or just a shared application. In my case the content needs to support different routes and different controllers for the different sites so I whipped up the following to add the desired routing to request.

module RequestMethods
  def host_name
    host = self.host.split(':')[0]
    host = "www.technomage.com" if host == "localhost"
    host = host.gsub(/.com\Z/, "")
    host = host.gsub(/\Awww./, "")
    puts "HostName: #{host}"
    host
  end
end
module Merb
  Request.class_eval "include(RequestMethods)"
end

And then I use the following to add a new matcher to the Behavior class to add to the Merb routing DSL.

class Merb::Router::Behavior

  # Creates a namespace for a route based on the requesting host
  #
  # ==== Parameters
  # name<String, Symbol>:: The name of the site, which is used as a
  # namespace also.
  # options<Hash>:: Optional hash, set :name if you want to override
  # what appears on the request host
  # &block::
  #   A new Behavior instance is yielded in the block for nested routes.
  #
  # ==== Block parameters
  # r<Behavior>:: The namespace behavior object.
  #
  # ==== Examples
  #   r.site :bookstore do |b|
  #     b.resources :accounts
  #     b.resource :email
  #   end
  #
  #   # www.super_bookstore.com/accounts
  #   r.site(:asuper_bookstore, :name=>"bookstore") do |b|
  #     b.resources :accounts
  #   end
  #---
  # @public
  def site(name, options={}, &block)
    name = options[:name] || name.to_s
    (name.empty? ? self : match(:host_name => name)).
      to(:namespace => name.to_s) do |r|
      yield r
    end
  end
end

Then I use it like so.

  r.site "technomage", :format => :html do | t |
    t.resources :posts, :name_prefix => "technomage_"
    AuthenticatedSystem.all_routes r
    t.match("/blog/:action/:id").to(:controller => "blog")
    t.match("/blog/:action").to(:controller => "blog")
    t.match("/blog").to(:controller => "blog").name(:technomage_blog)
    t.match("/start/contact").to(:controller => "start",
      :action => "contact").name(:technomage_contact)
    t.match(%r{/(start|home)}).to(:controller => "start").name(
      :technomage_home)
    t.match("/").to(:controller => "start").name(:technomage_root)
  end

Which allows such routes as:

Posted Sun Nov 23 21:11:11 -0800 2008

Update

In the last year I have been focusing almost exclusively on consulting work, as this bare-bones site attests.

I hope to get more time going forward for some posting on Merb which I am using on this site. I like many of the design choices. There are things it allows that require tricky patches in other frameworks. Look for some posts on routing and freezing as things progress.

I am also eagerly awaiting the opening of the Apple iPhone developer program. I have one app mostly there, and hope to get it into the store as soon as possible.

With RailsConf again upon us, I see that I need to allocate more time to the business and less time to the work, if I am going to find a good balance in keeping things moving. I have been neglecting the business for the work.

Posted Tue May 27 00:00:00 -0700 2008

iPhone

Like every self respecting geek I needed to get my iPhone on launch day. After waiting for 3 hours at an AT&T store I found out there were half as many phones as the people in line when I arrived! The wait was not that unpleasant actually. They took a list of people as they arrived and only required people to wait in order starting at about 5:45. So I got dinner, and had a chance to read a book for a bit before being on my feet for the last 2 hours. The people in line were interesting company, and the only real annoyance was the way AT&T handled the situation. They obviously were trying to grab as many sales as possible rather than letting them "get away" to an Apple store. So some people may have been willing to give them a name and wait for drop shipppment. Most of us were not. After calling the local apple store (we have 2), it turned out they had no line any longer and plenty of stock. A short drive later I had my iPhone and all was well with the work/wait. The device is so good in fact that we picked up one for my wife this morning. Unlike any other smartphone on the market we see this as being able to help organize our lives, not just be a phone with a few cool features.

So now I need to start developing the apps that we see as worthy of this tool and that will let us keep our lives organized and free of mundane tasks that were never worth doing on a computer that sat at home, or in a laptop bag. The fact that we have the iPhone with us at all times makes it uniquely able to take over those common tasks like grocery lists, to-dos, expenses, and money management. We already have design ideas for several of these that will exploit the unique aspects of the iPhone and its constant availability.

Posted Sat Jun 30 00:00:00 -0700 2007

Welcome

Starting a new company is always exciting and terrifying. Fortunately we have done this before, and know what to client needs, and actually having some time to write code, all play their part. It does feel good though to be out on our own again, not dependent on someone else to do it right, or to see things we see. Fear of responsibility is not one of our failings, which is why we can do this. Being accountable is not the same as being dependent. One has power the other does not. Corporate jobs are fine for a change when we get weary of having to go find the next project, but are not good as a steady diet.

Posted Fri Jun 15 00:00:00 -0700 2007