views:

328

answers:

2

I'm developing a Rails app that by default sets up user accounts to a subdomain of their choosing. As an option, they will be able to map their own full domain to their account.

So far this is how I have things set up. I am using subdomain-fu to power the routing:

# routes.rb
map.with_options :conditions => {:subdomain => true} do |app|
  app.resources # User's application routes are all mapped here
end

map.with_options :conditions => {:subdomain => false} do |www|
  www.resources # Public-facing sales website routes are mapped here
end

In addition to that, I am using the method described here to get the account being accessed, via subdomain or full domain:

before_filter :set_current_account

def set_current_account
  if request.host.ends_with? current_domain
    # via subdomain
    @current_club = Club.find_by_subdomain(current_subdomain)
  else
    # via full domain
    @current_club = Club.find_by_mapped_domain(request.host)
  end
end

I haven't got very far down the process of building this yet, but already I can see I am going to run into problems with routing. If request.host is some random.com domain then subdomain-fu is not going to route the appropriate routes?

I'm assuming this isn't that unusual a problem, so can anyone share how they have tackled this problem, or how I would configure my routes to do what I need it to?

+2  A: 

I ran into this problem, trying to do too much within a single application. You'll start doing conditionals in very odd places that you shouldn't have to. I decided to have 2 separate Rails apps that have the wildcard domain point to the User's application, then having www.domain.com and domain.com point to the public facing side. I know this doesn't quite "answer" your question directly.

Small code smell there that I can help you fix, if you add this to the top of that method:

return @current_club if defined?(@current_club)

It won't make a query for each time you try to access @current_club, it will return the result you already returned.

Garrett
Thanks for your answer. After experimenting with the other solution posted here I've come to the conclusion that you're right and for simplicities sake the best thing is to split it into two apps and do away with subdomain-fu.
aaronrussell
+1  A: 

You can write a Rack middleware that converts the domain into the subdomain before it hits the Rails application.

class AcountDetector
  def initialize(app)
    @app = app
  end

  def call(env)
    account = Club.find_by_mapped_domain(env["HTTP_HOST"])
    if account
      env["HTTP_HOST"] = "#{account.subdomain}.yourdomain.com"
    end

    @app.call(env)
  end
end

Then add that into environment.rb:

config.middleware.use AccountDetector
Peter
Thank you. I liked this answer so did some testing. Your middleware script works well, but unfortunately it was having some weird knock-on effects with sessions (using Authlogic).I've decided - reluctantly - to split the app into two separate apps.
aaronrussell