Foreign Domain Request Routing in Rails

Ruby on Rails routing with support for RESTful and named routes is one of the most useful features of Rails, but is also very frustrating and limited at times. I ran into this frustration a couple times while developing “QuantiPay”:quantipay, specifically when dealing with foreign domains and differentiating between http and https.

Routing Foreign Domains

The first requirement of QuantiPay involves routing and serving pages for foreign domains. For example if quantipay.com is our native doman, then payment.example.com would be a foreign domain. We use this functionality in QuantiPay to support fully-branded payment pages with custom URLs. I quickly found Foreign Domain Routing Plugin, which was an extension of Subdomain-fu, that extended Rails routing and quickly solved the problem of detecting and routing foreign domains.

Routing Request Protocol

The next requirement was a need to create multiple root routes differentiated by protocol. I wanted an https request with no URI do route by default to the application’s login page, while http requests should route to the front-facing homepage describing the service. I found Request Routing which solved this problem, while adding support for many additional properties usable in the :conditions hash.

Foreign Domain and Request Routing Combined

The problem I now faced was that these two plugins did not work together. I could route based on protocol, but I could not detect foreign domains, and vice-versa. I believe this is mainly due to the design of the request routing plugin which directly overrides the recognition_conditions method in the rails routing module, versus calling alias_method_chain as does Foreign Domain Routing.

To get these two to work together, I went ahead and forked the Foreign Domain Routing repository, and added Request Routing to it, as well as updated unit tests for both and packaged it as a gem. You can find the merged repository here.

Install as a gem via:

sudo gem install quantipay-foreign_domain_routing

Or add to environment.rb

config.gem “quantipay-foreign_domain_routing”, :source => “http://gems.github.com/”, :lib => “foreign_domain_routing”

Example usage in routes.rb

On line 2, we are mapping a default route for the front-end homepage describing the service, thus we only match this route if  :conditions => { :protocol => /http:/ }

On line 3, we are mapping a default route for the secure area of the site. This default route will send logged-in users to their dashboard, otherwise they will be redirected to the login page. We only want to match this route if it is being requested via our native domain and through the https: protocol.

On line 4, we are mapping all foreign domains to the payments controller. Anything that matches this rule will be redirected to SSL automatically by the ssl_requirement plugin.

This entry was posted in Ruby on Rails and tagged , , , , . Bookmark the permalink.

3 Responses to Foreign Domain Request Routing in Rails

  1. Bill Eisenhauer says:

    Interesting stuff. I have to do something similar on a site which makes heavy use of SSL. In implementing this foreign domain mapping technique, don’t you have SSL certificate issues? Curious to know how you would overcome that problem.

  2. Joe Scharf says:

    Hi Bill,

    For multiple foreign domains and SSL Certs, you’re pretty much left with no other option than to have additional public IPs assigned to your server for hosting multiple ssl certs. That is, at least until SNI becomes an option, and some quick searches seem to indicate that it might be possible to get mod_gnutls working

  3. Bill Eisenhauer says:

    So how does your company manage IPs and SSL certs given that limitation?

    I did some research and its possible that SNI could solve our problem, but that only overcomes the IP scalability issue. Well, actually, I’m not sure if it does or not. I’m not sure what the cert(s) need to be under that approach. At least now, most modern browsers support SNI, so we’re nearly out of the woods.

    Unfortunately, we are trying to be a SaaS where encryption is needed. Allocating an IP address per customer obviously won’t work.