#123 Subdomains (revised)
In Rails 3.1 subdomains are easier than ever to use. Here I show how to route a subdomain to a specific controller action, generate links, nest resources, and more.
- source codeProject Files in Zip (86.1 KB)
- mp4Full Size H.264 Video (15.9 MB)
- m4vSmaller H.264 Video (8.29 MB)
- webmFull Size VP8 Video (10.7 MB)
- ogvFull Size Theora Video (18.4 MB)
Why Ryan used find_by with a bang in the end? Is it for raising a RecordNotFound exception? What are the benefits of this practice?
As you guessed, the bang on the find_by_subdomain method is so it will raise RecordNotFound if the given subdomain does not exist.
A benefit of this would be so you could rescue_from RecordNotFound in the ApplicationController (or a specific controller) and redirect the user to another page with a flash message.
This has the added benefit of keeping your code DRY so you don't dirty up your controller actions by checking for a valid result and taking action accordingly.
Mike's answer is awesome, just adding my two cents:
The find_by isn't supposed to fail in any way, you expect to find a blog for your subdomain. If it fails you probably want something to happen (an exception rather than a fallback).
xxx_url(:subdomain => false) in rails 3.1
doesn't work anymore for me. Any ideas?
To be more specific, if i use a redirect_to in my controller action
it redirects me to the requested url but doesn't remove the subdomain
There is a closed issue on this matter. See https://github.com/rails/rails/issues/2025
I hope this is getting into rails 3.2.
In the meantime using the :host option works for me:
I keep getting
WARNING: Can't verify CSRF token authenticitywhen submeting a form from the root domain (domain.com) to a subdomain (example.domain.com). I found a way to share the cookies in all subdomains (
domain: :allin session_store.rb), but i can't found a way to share the token. Anyone can help me?
I'm trying to figure it out this problem in here: http://stackoverflow.com/questions/8931066/cant-post-a-form-to-a-different-subdomain-via-ajax-warning-cant-verify-csrf
Is there a way to not have all other routes respond to the subdomain and viceversa? Since now that same content would get served on two urls and considered duplicated by search engines.
update: I've been doing some research but nothing found, I'm using a basic redirection depending on controller_name and request.subdomain in a before_filter in application_controller
Thanks for your reply. Already tried the constraints but it didn't work out.
Forgot to do the follow up. It was a problem with a gem modifying routes which deleted the subdomain constraints.
What gem was it? I've been having perhaps the same problem and haven't seen any solutions.
anyone know if its possible to override CSS based on a subdomian?
Could you simply make an if statement around your stylesheet_link_tag?
So I am having trouble linking to static pages. I am trying to do something really simple, subdomain would be a static page and then link between several other static pages within that subdomain. I have it working with subdomain.domain.com/ and subdomain.domain.com/static-page, but how do I link to that?
static page linking
<%=link_to "Subdomain", root_url(:subdomain => "subdomainRouteName") %>
<%=link_to "Home", root_url(:subdomain => false) %>
Great screen casts, thank you!
I've been out of Rails for about a year and just trying to get back up to speed on what has changed and new approaches. I've written a couple small applications that are deployed from home (small audience, like my golf group), but I never completed what got me started on Rails - trying to rewrite an application that was and still is in 4D (aka 4th Dimension) using Active4D as the web access to 4D.
While I am retired, it still bugs me that I never got that conversion completed and occasionally waste a little time thinking of new approaches. This screen cast and the multitenecy got me thinking about yet another approach and is close to what I did years ago for my golf group maxwell.golfgaggle.com, playing with subdomains for groups and accounts (this would have helped at that time).
The application is to support AIDT aidt.edu which is an Alabama State agency that is part of Alabama's economic development team. If short it recruits and screens prospective employees for Alabama businesses (think Mercedes, Honda, Hyundai and many other smaller companies who have located in Alabama).
What I've potentially found this week is that routes, namespaces and subdomains are our friends for solving certain kinds of authentication and authorization problems. The web interface basically had two virtual hosts. jobs.aidt.edu the external site that candidates for job training leading to employment could apply, and an intranet application used to manage parts of the process over the web. The goal was to expand this into several other virtual hosts to enhance the process (project. to allow company users to interact with the process for their company project, instructor. to allow contract instructors to do some things, and then admin. to shield some stuff from the employee users. The above links are to the Active4D site, Rails is still just a thought and AIDT's remaining staff is undermanned - why a try to push them sometimes.
I threw off Devise several years ago and went with Simple Authorization (scratch) and CanCan. While it states that CanCan does not work well with namespace, I think I can get around it because namespace does the majority of the authorization by separating the database. The subdomain/namespaces jobs, project an instructor have limited access to just a few models and the controllers control the access. If they are logged in, thats all they can do. Admin just protects some stuff, but the intranet is pretty wide open and lends itself to CanCan type authorization.
My current approach is:
User is polymorphic as loginable to Citizens, Employees, Contacts and Instructors (maybe others) and only Citizens (jobs namespace) can register, all others are invited.
Most routes are constrained by subdomain
Have not set up CanCan yet, but it appears that Read Write Manage, etc will take care of most requirements. Non CRUD actions like 'invite', 'drop', 'progress' can also be handled.
This really applies to several screen casts but just thought I'd stick it here.
Ryan, thanks for your work. I'll never be a Rails expert but you certainly open my eyes to different ways of solving problems that sometimes seem unique.
Nice screencast but I don't like:
lambdain the routes.rb file
2. Problem with adding
subdomain: falsein every routing that I want to clean urls from subdomain
3. Problem with changing every
_urlalso for cleaning urls (many hours of work in large project).
ad. 1. Instead of using the
lambdaI can use smart regular expression:
/^(?!www$)(.+)$/idoesn't allow to handle main domain with
www. Really nice, isn't?
ad. 2. I prefer to add following line in
Now using subdomain is disabled by default. I don't need to add
subdomain: falsein many lines in
ad. 3. I prefer to create file
url_helper.rbwith a few lines of code:
Now I do not have to change thousands of links :-) ufff :-))
It works for me. Do you like it?
P.S. I'm using Rails 3.2
This is a really great solution! I've been searching all over for something like this and managed to implement without a hitch. One question though - is there any way to stop if spawning a new page every time you click on a link, and so it simply send you to the link path rather than creating another separate page with url?
Thank your for your info!
I'm not sure if I understand correctly.
Can you give me an example how it works and how it should work?
In the meantime I'll give you an idea how to make
www.subdomain by default. Let's suppose:
1. First you open page that has url - for example
<a href="http://mark.lvh.me:3000/">Show Mark</a>). You click it and new page opens.
2. Then you click link
http://www.lvh.me:3000/adam(page has full url path -
<a href="http://www.lvh.me:3000/adam">Show Adam</a>)
3. New page opens and it has only paths for example
<a href="/adam">Show Adam</a>. It doen't have html code like
<a href="http://lvh.me:3000/adam">Show Adam</a>- I guess you gets full url in this point.
How I did it?
1. added line
2. defined method
It looks like that:
There is used
DomainFormatValidator::check_numeric_domainmethod in the
The reason is you can use numeric addresing like 127.0.0.1:3000 for opening your page. In this case we cannot add
Besides we chec if domain is blank. If true the we do nothing.
It works fine on my local, development environment. I've never tested it in the poduction environment, but I'm going to do that very soon :)
I hope it is clear. If not let me know :)
Has anyone had success with multiple subdomains having separate sessions as per this question on stackoverflow? http://stackoverflow.com/questions/14573761/rails-separate-sessions-over-multiple-subdomains
This railscasts doesn't cover how to handle config.action_controller.asset_host which is used when emailing for instance.
You want the email to link to the asset in the correct subdomain.
The solution I'm thinking to use looks like this:
Though I'm not quite sure how to write a test for this.
I'm having trouble because heroku is requiring the "www." subdomain.
I am having success with pow locally, but when I try to go to the URL in production it fails and the browser can't resolve the URL.
has anyone else encountered this?
I had the same problem with heroku, have you found a solution?
I'm in the same boat. Adam or Matt could you please post if you found a solution? Thanks.
not sure if this is relevant but did you set heroku up to use subdomains such as ***.myapp.com. You can set it up by using wildcard domains as per herokus documentation
Thanks. What I was trying to do is not possible with Heroku at the moment: Sub-sub domains aren't possible on Heroku default domain (yourappname.herokuapp.com), and you need to use the custom record for that
What if you set config.action_dispatch.tld_length = 2 for herokuapp hosted sites, such as staging.rb? For production, I'd assume you won't use herokuapp.com so tld_length = 1 still works?
I am trying to validate subdomain in Rails 4 but getting exception, can anyone plz help me ?
Once setup, running a subdomain is as easy as:
ngrok -subdomain=mysubdomain 3000
https://mysubdomain.ngrok.com -> 127.0.0.1:3000
http://mysubdomain.ngrok.com -> 127.0.0.1:3000
I used it to test PayPal's IPN for recurring subscriptions.