lost password?

home
•  xaraya
•  rails +
•  django
•  webdev
•  xamp
•  musings

rss
Tag this page
   

ยป Blogs that link here
last modified: Dec 13, 2007
(first posted: Dec 11, 2007)
(1741 Reads)
keywords: routes subdomains
Permalink

Url For Subdomains

You can override the url_for options to set subdomains in named routes.

Using subdomains to find objects in actions is as easy as nested resources. Whereas a nested resource might expect a path like "/foo/:foo_name/bars/:id" so in the BarsController you add a before_filter

class BarsController < ApplicationController
  before_filter :find_foo
  def find_foo
    @foo = Foo.find_by_name(params[:foo_name]) if params[:foo_name]
  end
  ...

But instead if you want to use a url like "http://foodoo.mysite.com/bars/:id", you can rewrite find like so:

  def find_foo
    @foo = Foo.find_by_name( self.request.subdomains[0] ) 
  end

Cool.

In the latter case, you don't need to specify a nested resource in routes.rb at all. That is, routes.rb doesn't need to know anything about the subdomain, you just map.resources :bar , giving you named routes like bar_url(@bar) (=> http://www.mysite.com/bars/123) and bar_path(@bar) (=> /bars/123).

Now, how do you force the named routes to set the subdomain? Taken further, lets say some links in your app will use the foo.mysite.com host, and others should use www.mysite.com. Handle this by overriding the default_url_options to set the :host option. For example, in controllers/application.rb

  def default_url_options( options={} )
    subdomain = (@foo.nil? or options[:controller] == 'pages') ? 'www' : @foo.name
    { :host => "#{subdomain}.#{request.domain}" }
  end

Now bar_url(@bar) will generate "http://fooname.mysite.com/bars/123", provided you'd defined an instance variable @foo beforehand. But pages_url(@page) will generate "http://www.mysite.com/pages/456"

Note bar_path (vs bar_url) is used for relative urls, and :host is ignored. So if you know a link can be relative to the host of the current page, use _path, but if you know it is different or unsure, use the _url version to include the host name in the generated url.

Caveats

After using this technique for a day or two I've run into some problems. There appear to be cases where default_url_options is not used at all, so my subdomain was not getting set.

Usually it's fine calling foo_url from a view template or a controller; it did not work when calling foo_url from a helper method. Digging further I see there are two versions of url_for in rails:

In actionpack/lib/action_controller/url_rewriter.rb url_for does

options = self.class.default_url_options.merge(options)

In actionpack/lib/action_view/helpers/url_helper.rb does NOT call default_url_options

Thus depending where you call bar_url, you may or may not get the subdomain replaced. The risks of trying to play under the hood of a speeding locomotive...

Solution

But, I also realized I usually need my links to be relative to the current subdomain, and only some very specific cases when it's changing. So, it'd be ok to be explicit in these cases rather than the general url_for approach. Now, I just do this:

in application.rb

  def www_url( path='' )
subdomain_url( 'www', path )
end

def subdomain_url( subdomain, path='' )
"http://#{subdomain}.#{request.domain}#{request.port_string}#{path}"
end

 

To force a link to be the www subdomain,

<%= link_to "About this site", www_url( home_path )) %>

To link to a specific subdomain,

<%= link_to "Your account", subdomain_url(@account.name, foo_path)) %>

Word.

 

 

 

Url For Subdomains

Posted by: Deepak Jois on April 20, 2008 12:00 PM
You may be interested in this ticket I just filed. http://rails.lighthouseapp.com/projects/8994/tickets/22-default_url_options-is-b eing-ignored-by-named-route-optimisation

#

Post a new comment

: This is not spam

Name :