Skip to content

Instantly share code, notes, and snippets.

@sj26
Created February 29, 2012 10:38
  • Star 7 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save sj26/1939812 to your computer and use it in GitHub Desktop.
Subdomains in Rails 3

Subdomains in Rails 3

Are still a nightmare to get tested, etc.

To share sessions across subdomains you need to set the session options during the request so you know what domain you're sharing across. This means we still need to do it with a before_filter, or something similar. It looks like you should be able to set :domain => true in config/initializers/session_store.rb to do this instead but Devise does not support it yet as far as I can see.

Here I'm using subdomains with a custom url_for extension which means from "http://www.smackaho.st" root_path would be "/" while from "http://admin.smackaho.st" root_path would be "http://www.smackaho.st/".

In cucumber this is forced to always qualify the full URL with the subdomain. It also rewrites the port in/out as neccessary to cope with Capybara's server using an alternate port (used by Selenium for javascript testing etc). The project I'm on is still using web_steps (sigh) so I had to touch the "should be on" step definition to cope with this too.

class ApplicationController < ActionController::Base
before_filter :set_session_options_domain
protected
def set_session_options_domain
request.session_options[:domain] = request.domain
end
end
module SubdomainHelper
# Rails constructs subdomain-based routes correctly, but sometimes
# need a kick in the pants when the subdomains aren't matching
def url_for options=nil
if options.kind_of? Hash and options.has_key? :subdomain and options[:_path_segments] and options[:_path_segments][:subdomain] != options[:subdomain]
options[:only_path] = false
end
super
end
end
My::Application.routes.extend SubdomainHelper
Then /^(?:|I )should be on (.+)$/ do |page_name|
expected_path = path_to(page_name)
# We may expect a fully-qualified URL, in which case we devine
# the current URL taking the capybara server port, query and
# fragment out of the equation.
current_path = URI.parse(current_url)
if expected_path =~ /\Ahttp/
current_path.port = nil
current_path.query = nil
current_path.fragment = nil
current_path = current_path.to_s
else
current_path = current_path.path
end
if current_path.respond_to? :should
current_path.should == expected_path
else
assert_equal expected_path, current_path
end
end
# Capybara runs a server which selenium tests against
# on another port, but we still need to use subdomains.
#
# We use the free smackaho.st domain which wildcards
# to 127.0.0.1, and factor in Capybara's alternate port.
Capybara.default_host = "http://www.smackaho.st"
ActionDispatch::Integration::Session::DEFAULT_HOST.replace "www.smackaho.st"
# ALWAYS use absolute urls for cucumber. It just
# makes things easier. This fixes rack-test-based
# scenarios involving subdomain routes.
module CucumberSubdomainHelper
def url_for options={}
if options.kind_of? Hash
options[:only_path] = false
end
super
end
end
My::Application.routes.extend CucumberSubdomainHelper
# Do some magic between `visit_url <blah>` and what
# capybara tells selenium. This fixes selenium (javascript)
# based scenarios involving subdomain routes.
module CapybaraSubdomainHelper
extend ActiveSupport::Concern
included do
alias_method_chain :url, :subdomain
end
def url_with_subdomain path
if path =~ /^http/
url = URI.parse path
url.host ||= host
url.port = port
url.to_s
else
url_without_subdomain path
end
end
end
Capybara::Server.send :include, CapybaraSubdomainHelper
root / home#show {:subdomain=>"www"}
admin_root / admin/dashboard#show {:subdomain=>"admin"}
My::Application.routes.draw do
scope :constraints => {:subdomain => /\A(www|)\Z/}, :defaults => {:subdomain => 'www'} do
root to: "home#show"
end
scope :module => :admin, :as => :admin, :constraints => {:subdomain => "admin"}, :defaults => {:subdomain => "admin"} do
root to: 'dashboard#show'
end
end
@rosskevin
Copy link

This appears to be incompatible with Capybara 2.1.0 and Rails 3.2.13. Specifically, the:

Capybara::Server.send :include, CapybaraSubdomainHelper

Fails, with:

undefined method `url' for class `Capybara::Server' (NameError)

Im still looking at how this can be altered to work...but I'm new to rails so it's a bit of a learning curve...

@meatherly
Copy link

@rosskevin Did you ever find a solution to this? I'm experiencing the same problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment