#221
Jul 05, 2010

Subdomains in Rails 3

It is now possible to add subdomains to Rails 3 without the use of additional plugins. Learn how in this episode.
Download (18.8 MB, 13:55)
alternative download for iPod & Apple TV (18.5 MB, 13:55)

Resources

# routes.rb
constraints(Subdomain) do
  match '/' => 'blogs#show'
end

# lib/subdomain.rb
class Subdomain
  def self.matches?(request)
    request.subdomain.present? && request.subdomain != "www"
  end
end

# app/helpers/url_helper.rb
module UrlHelper
  def with_subdomain(subdomain)
    subdomain = (subdomain || "")
    subdomain += "." unless subdomain.empty?
    [subdomain, request.domain, request.port_string].join
  end
  
  def url_for(options = nil)
    if options.kind_of?(Hash) && options.has_key?(:subdomain)
      options[:host] = with_subdomain(options.delete(:subdomain))
    end
    super
  end
end

# application_controller.rb
include UrlHelper

# config/initializers/session_store.rb
# requires Rails 3.0 RC or head
Rails.application.config.session_store :cookie_store, :key => '_blogs_session', :domain => :all

# change top level domain size
request.domain(2)
request.subdomain(2)
Rails.application.config.session_store :cookie_store, :key => '_blogs_session', :domain => "example.co.uk"
<!-- blogs/index.html.erb -->
<%= link_to blog.name, root_url(:subdomain => blog.subdomain) %>

<!-- blogs/show.html.erb -->
<%= link_to "All Blogs", root_url(:subdomain => false) %>

RSS Feed for Episode Comments 45 comments

1. Золзаяа Jul 05, 2010 at 01:27

Thanks for this post.


2. docgecko Jul 05, 2010 at 02:23

Thanks for this Ryan!

I've been trying to get Devise and subdomains to work together, by using one of the Subdomain plugins, but not managed to get there fully. Going to have a go using your approach now and see how I get on.

Keep up the great casts, they are always mega helpful!


3. jim Jul 05, 2010 at 03:32

Great post Ryan! Thanks!


4. tomekw Jul 05, 2010 at 05:03

There is a typo in "http://github.com/ryanb/railcasts-episodes/tree/master/episode-221" link: it should be "http://github.com/ryanb/railscasts-episodes/tree/master/episode-221" (missing "s" in railscasts-episodes".


5. Marcelo Silveira Jul 05, 2010 at 06:41

Great, thanks!


6. Wade West Jul 05, 2010 at 07:41

Another great screencast Ryan. Thank You. And as a side note, today's my birthday :)


7. Emerson Lackey Jul 05, 2010 at 08:54

Finally got Rails 3 working with RVM. Stopped using my local Passenger installation and now I'm really enjoying the flexibility of jumping around to different versions of Ruby/Rails.

Currently developing an app that requires account level subdomains and was unhappy with the options in Rails 2.3...

Looking forward to Rails 3 RC, thanks again for all the awesome screencasts!


8. Jaime Jul 05, 2010 at 09:03

Cool tricks, Ryan.

You just gave me some ideas to try out on my pet projects :)


9. Ryan Bates Jul 05, 2010 at 09:35

@tomekw, thanks, fixed!


10. dotemacs Jul 05, 2010 at 09:55

Great vid, was meaning to have a look at the subdomains in rails3, but you just summed it up nicely.

Also plus points for picking up on smackaho.st :)


11. dhc Jul 05, 2010 at 11:26

In this line of your code:

options[:host] = with_subdomain(options.delete(:subdomain))

what does options.delete() do? It doesn't seem intuitive, which is rare in Ruby.

--dhc


12. Alexander Jul 05, 2010 at 12:14

Is it possible to use domain size 0? I need to show different content depending on domain name, but the main part of the site is the same.


13. Gigamo Jul 05, 2010 at 14:47

@dhc: It removes the passed element from the hash and returns it. See http://ruby-doc.org/core/classes/Hash.html#M002870


14. bluecoda Jul 05, 2010 at 20:07

Very great episode. i've been waiting this for a long time.Thank you very much~Very good job


15. Alexey Poimtsev Jul 06, 2010 at 00:45

Hi, Ryan.
I've wrote similar article some months ago (http://bit.ly/ajGym2 - sorry, only Russian version, but you can use Google Translate) but there are some problems with session sharing between subdomains in Opera browser - unfortunately Opera cannot read cookies from sibling domain - it means if you set cookie for dom1.example.com cookie cannot be read from dom2.example.com


16. Frederic Jul 06, 2010 at 03:20

@Alexey Poimtsev:

There's a blog article on my.opera.com that describes how the Opera browser deals with cookie sharing between subdomains.

To sumarize (very quickly) the article: any *.example.tld subdomains are considered as siblings (and can share domain=.example.tld cookies) if the example.tld domain has a registered IP address in DNS.

The reality is a little more complicated, so the
http://my.opera.com/yngve/blog/show.dml/267415 article deserves a reading.


17. davidrv Jul 06, 2010 at 04:38

Nice! Thx :)


18. Bagwan Pankaj Jul 06, 2010 at 06:12

Nice post. Thanks


19. Jamie Hill Jul 06, 2010 at 07:00

Thanks Ryan!

I really wish I had this to hand a couple of weeks ago when trying to figure out the subdomain stuff in Rails 3. This has helped me to tidy up my code somewhat.

I'd really like to see the ":subdomain" option on url helpers as a patch for Rails 3, will you be submitting? ...If not I may do so as it's super useful.

Thanks again.


20. Ryan Bates Jul 06, 2010 at 10:40

@Alexander, I mention changing the top level domain size at the end of the episode. I haven't tested it, but passing "0" for the tld size should work.

@Jamie, I think the problem with adding a built-in :subdomain option is that the top level domain size is not easily configurable.

That said, I think a ticket on configuring the default tld size along with this would be great. I don't have plans to do this so feel free to.


21. Mario Uher Jul 07, 2010 at 00:01

I think

constraints(Subdomain) do
  match '/' => 'blogs#show'
end

can be even shorter, like

constraints(Subdomain) do
  root :to => 'blogs#show'
end


22. Roland Jul 08, 2010 at 04:56

If you have to deal with various top level domains and third level assignments in parallel (.e.g. some have .com, some others co.uk) you may want to use the public suffix library from:

http://www.simonecarletti.com/blog/2010/06/public-suffix-list-library-for-ruby/

This is far better than hardcoding the length in your app and also used by browser vendors already.

hth,
Roland


23. wout fierens Jul 08, 2010 at 10:45

You made my day Ryan! Thanks to you I moved a rather complex Rails app with various subdomain implementations from 2.3.8 to 3 in less than a day.


24. Matt Beedle Jul 09, 2010 at 11:12

I just figured out how to get this working and blogged about it a couple of days before you did this! I like your solution more though. In case anyone is interested, I also blogged about how to test it with cucumber/capybara: http://mattbeedle.com/2010/07/04/testing-subdomains-with-cucumber-cabybara-and-rack-test


25. Steve Jul 10, 2010 at 09:17

I just get an error...

uninitialized constant Subdomain (NameError)


26. Samuel Lebeau Jul 12, 2010 at 06:48

Great screencast as usual, thanks Ryan !

On Mac OS X, "*.127localhost.*" resolves to 127.0.0.1 too: it's really helpful to test applications against both subdomains and TLDs.


27. Igor Jul 16, 2010 at 02:10

Thanks for this post, but it don't work for ActionMailer.

Here my path:
http://gist.github.com/478169


28. güncel 2010 Jul 19, 2010 at 04:02

güncel 2010 sitelerini buradan inceleyebilirsiniz. Bu sebeple bizde silere güncel 2010 sitlerini ve sub domainlerini yayınlayalım sitedik. Umarız faydalı olur ve yaralarnırsınız.


29. elvankent halı yıkama Jul 22, 2010 at 00:13

Very pleased to be here!


30. air max 2009 Jul 24, 2010 at 00:08

in the best max shoes


31. jordan basketball shoes Jul 24, 2010 at 00:09

best jordan store


34. compaq laptop battery Jul 29, 2010 at 02:12

I am happy to find the site and I think it is very useful code to us.Thank you.


34. wholesale jeans Jul 31, 2010 at 01:24

I am apreciating it very much.I have never read such a lovely article and I am coming back


35. George Ornbo Aug 01, 2010 at 05:49

If you get the error

uninitialized constant Subdomain (NameError)

it seems that in the later versions of the Rails 3 beta or the edge version the routes file doesn't autoload /lib/subdomain.rb

Adding

require 'subdomain'

before the routes block fixes this.


35. boots Aug 01, 2010 at 19:29

 or the edge version the routes file doesn't autoload /lib/subdomain.rb

Adding


36. Doug Mayer Aug 02, 2010 at 11:10

In Rails 3.0.0.rc there seems to be an issue using :domain => :all - it flips out with an InvalidAuthenticityToken error. Using :domain => ".smackaho.st" works for the time being.

Per https://rails.lighthouseapp.com/projects/8994/tickets/5147-the-all-domain-option-for-the-cookie-session-store-doesnt-allow-non-standard-tlds-like-local-or-couk


37. acekard 2 Aug 02, 2010 at 20:21

http://www.ndscardstore.com/Acekard
http://www.ndscardstore.com/R4
http://www.ndscardstore.com/DSTT


38. airjordanshoes Aug 03, 2010 at 05:51

 <a href="http://www.airjordanpower.com/air-jordan-dub-zeros-c-26" title="jordan dub zeros">jordan dub zeros</a>
 <a href="http://www.airjordanpower.com/air-jordan-2010-c-25" title="air jordan 2010">air jordan 2010</a>
 <a href="http://www.airjordanpower.com/air-jordan-2009-24" title="air jordan 2009">air jordan 2009</a>


39. pumashoes Aug 03, 2010 at 05:53

nice


40. dailysneakers Aug 03, 2010 at 05:56

<a href="http://dailysneakers.com/">sneaker news</a> <a href="http://dailysneakers.com/">puma shoes news</a> <a href="http://dailysneakers.com/">air jordan shoes news</a>


41. buy chanel handbags Aug 04, 2010 at 01:55

Thanks for this Ryan!

I've been trying to get Devise and subdomains to work together, by using one of the Subdomain plugins, but not managed to get there fully. Going to have a go using your approach now and see how I get on.

Keep up the great casts, they are always mega helpful!


42. wholesale DG bags Aug 06, 2010 at 01:27

your artical is very interesting, and i also have a brilliant website to share with you. http://www.worthmall.com .

thanks. you won't be a loss to visit it. maybe you can get something you are favorite.


45. cheap coogi Aug 09, 2010 at 10:19

Here we have popular Polo T-shirt.


46. UGG Boots on sale Aug 10, 2010 at 18:38

Gooooooooooooooooooood luck ~~!!


47. thb Aug 12, 2010 at 04:37

@george (#35) : I agree.

It's weird that in the session_store.rb file, :domain => :all doesn't work for me (in Edge). :domain => 'lvh.me' does work though... any insights about this?

@docgecko (#2) : devise works fine for me here.


48. oppo Aug 15, 2010 at 08:38

This was really useful. Thanks Ryan!


49. Daniel Kehoe Aug 17, 2010 at 15:13

@Doug Mayer (#36):
@thb (#47):

:domain => :all doesn't work in the Rails 3 release candidate (it results in an InvalidAuthenticityToken error). The issue is resolved in Rails 3 master on GitHub with commit fd78bb72704554737117 by Bryce Thornton on 14 Aug 2010.


50. Rails3 Subdomains Devise Authentication Aug 17, 2010 at 15:26

Thanks, Ryan! For anyone who needs more, I put together a Rails 3 example app (with a detailed walk-through tutorial) that shows how to set up subdomains in Rails 3 using Devise for authentication: http://github.com/fortuity/rails3-subdomain-devise (click above for the link). For anyone who needs a quick start for blog-style subdomains using Rails 3.


51. Rip Blu-ray for Mac Aug 18, 2010 at 01:26

Thanks,it's so good.
suport!


52. wholesale new era caps Aug 20, 2010 at 19:57

It's funny how we adopt words and adapt our lexicon to the times. This is a very useful slant on things.


53. converse all star Aug 20, 2010 at 20:36

love converse all star,love yourself.Warm welcome.


54. converse all star Aug 20, 2010 at 20:53

love converse all star,love yourself.High quality low price.It's fit for you.


55. tile floor vacuum Aug 24, 2010 at 10:24

The blog article very surprised to me! Your writing is good. In this I learned a lot! Thank you!


56. cheap clothes Aug 24, 2010 at 19:07

David Heinemeier Hansson..thanks


57. PDF to Images Converter Aug 24, 2010 at 22:52

Some times, to a certain need, we have to convert PDF to image for enjoyment.


58. louis vuitton shoes Aug 26, 2010 at 23:20

Thanks for sharing your article. I really enjoyed it. I put a link to my site to here so other people can read it. My readers have about the same interets


59. mbt shoes sale Aug 28, 2010 at 09:50

love yourself.Warm welcome.


60. cheap mbt shoes Aug 28, 2010 at 10:10

InvalidAuthenticityToken error). The issue is resolved in Rails 3 master on GitHub with commit fd78bb72704554737117 by Bryce Thornton on 14 Aug 2010.


61. cheap ugg boots sale Aug 28, 2010 at 10:19

all doesn't work for me (in Edge). :domain => 'lvh.me' does work though... any insights about this?

@docgecko (#2) : devise works fine for me here.


62. snow boots Aug 30, 2010 at 20:08

Stopped using my local Passenger installation and now I'm really enjoying the flexibility of jumping around to different versions of Ruby/Rails.


63. herve leger dress Aug 30, 2010 at 20:10

Thanks for sharing your article. I really enjoyed it. I put a link to my site to here so other people can read it.


64. louis vuitton sunglasses Sep 01, 2010 at 22:38

Extremely great post, really beneficial stuff. Never thought I’d find the facts I would like in this article. I’ve been looking all over the net for some time now and was starting to get irritated.

Add your comment:

(SKIP THIS ONE)

(required)

(not shown)


(use pastie or gist for code)

sponsored by:
if you want to help:
required:
Get Quicktime Player
Give Back to Open Source