I figured out how to sort this issue.

In my before block in my specs I simply added:

before(:each) do
  @request.host = "#{mock_subdomain}.example.com"
end

This setups up the request.subdomains.first to be the value of the mock_subdomain.

Hope someone finds this useful as its not explained very well anywhere else on the net.


I know this is a relatively old question, but I've found that this depends on what kind of test you're running. I'm also running Rails 4 and RSpec 3.2, so I'm sure some things have changed since this question was asked.

Request Specs

before { host! "#{mock_subdomain}.example.com" }

Feature Specs with Capybara

before { Capybara.default_host = "http://#{mock_subdomain}.example.com" }
after  { Capybara.default_host = "http://www.example.com" }

I usually create modules in spec/support that look something like this:

# spec/support/feature_subdomain_helpers.rb
module FeatureSubdomainHelpers
  # Sets Capybara to use a given subdomain.
  def within_subdomain(subdomain)
    before { Capybara.default_host = "http://#{subdomain}.example.com" }
    after  { Capybara.default_host = "http://www.example.com" }
    yield
  end
end

# spec/support/request_subdomain_helpers.rb
module RequestSubdomainHelpers
  # Sets host to use a given subdomain.
  def within_subdomain(subdomain)
    before { host! "#{subdomain}.example.com" }
    after  { host! "www.example.com" }
    yield
  end
end

Include in spec/rails_helper.rb:

RSpec.configure do |config|
  # ...

  # Extensions
  config.extend FeatureSubdomainHelpers, type: :feature
  config.extend RequestSubdomainHelpers, type: :request
end

Then you can call within your spec like so:

feature 'Admin signs in' do
  given!(:admin) { FactoryGirl.create(:user, :admin) }

  within_subdomain :admin do
    scenario 'with valid credentials' do
      # ...
    end

    scenario 'with invalid password' do
      # ...
    end
  end
end

In rails 3 everything I tried to manually set the host didn't work, but looking the code I noticed how nicely they parsed the path you pass to the request helpers like get. Sure enough if your controller goes and fetches the user mentioned in the subdomain and stores it as @king_of_the_castle

it "fetches the user of the subomain" do
  get "http://#{mock_subdomain}.example.com/rest_of_the_path"
  assigns[:king_of_the_castle].should eql(User.find_by_name mock_subdomain)
end