Rails 3.1 Multitenancy routes - ruby-on-rails

I have a Rails 3.1 multi-tenancy app with a domain that I'll call mydomain.com. With this I would like to create the following routes but keep coming unstuck
default root for www.mydomain.com and mydomain.com should go to a controller called home or similar
default root for *.mydomain.com (except www) should go to a sesions/new route
default root for *.mydomain.com (except www) when logged in will go to a dashboard controller or simialar
Can anyone help with a way of achieving this?

This is pretty similar to what you're looking for: http://maxresponsemedia.com/rails/setting-up-user-subdomains-in-rails-3/.
Edit
It appears that the link is now dead (which is why we should post more than just links!), but I was able to find it in the WayBackMachine. Here are the code examples that it had.
First, we define a couple of constraints for subdomains and the root domain:
# /lib/domains.rb
class Subdomain
def self.matches?(request)
request.subdomain.present? && request.subdomain != "www" && request.subdomain != ""
end
end
class RootDomain
#subdomains = ["www"]
def self.matches?(request)
#subdomains.include?(request.subdomain) || request.subdomain.blank?
end
end
Then, in our routes.rb, we direct the subdomains to a websites controller, but any requests to domains related to the main site get sent to the static pages that are configured for the app.
# config/routes.rb
# a bunch of other routes...
# requiring the /lib/domains.rb file we created
require 'domains'
constraints(Subdomain) do
match '/' => 'websites#show'
end
constraints(RootDomain) do
match '/contact_us', :to => 'static_pages#contact'
match '/about', :to => 'static_pages#about'
match '/help', :to => 'static_pages#help'
match '/news', :to => 'static_pages#news'
match '/admin', :to => 'admin#index'
end

Related

Separate Domain for Namespaced Routes in Rails 4

I'm working on a Rails 4 app. One part of the app is a customer portal that has to be accessed from a separate domain.
I have everything working fine by navigating to domain.com/cp. The routes use namespaced controllers:
namespace :cp do
get :dashboard, to: 'dashboard#index', path: ''
...
end
How should I set up DNS records and change the routes definition so that another domain cpdomain.com points to domain.com/cp properly (no redirecting).
Thanks.
This answer can be useful for the rails routes problem:
Rails routing to handle multiple domains on single application
Shortened:
1) define a custom constraint class in lib/domain_constraint.rb:
class DomainConstraint
def initialize(domain)
#domains = [domain].flatten
end
def matches?(request)
#domains.include? request.domain
end
end
2) use the class in your routes with the new block syntax
constraints DomainConstraint.new('mydomain.com') do
root :to => 'mydomain#index'
end
root :to => 'main#index'
or the old-fashioned option syntax
root :to => 'mydomain#index', :constraints => DomainConstraint.new('mydomain.com')

Exclude all other resources from subdomain in Rails

I have a Rails 4.0 app with that allows users to access blogs through subdomains. My routes currently look like this:
match '', to: 'blogs#show', via: [:get, :post], constraints: lambda { |r| r.subdomain.present? && r.subdomain != 'www' }
resources :foobars
Now, when I navigate to somesubdomain.example.com I am indeed taken to the showaction of the blogs controller action, as expected.
When I navigate to example.com/foobars I can access the index action of the foobars controller, as expected.
However, I only get a behavior I do not desire:
When I navigate to somesubdomain.example.com/foobars, I can still access the the index action of foobars controller.
Is there a way to limit or exclude all resources that I do not specifically allow for a particular subdomain (i.e. somesubdomain.example.com/foobars will not work unless otherwise specified).
Thanks!
If you need to define a specific subdomain to exclude from a set of routes you can simply do this (uses negative lookahead regex):
# exclude all subdomains with 'www'
constrain :subdomain => /^(?!www)(\w+)/ do
root to: 'session#new'
resources :foobars
end
Or similarly, to define a specific subdomain to include a set of routes you could do this:
# only for subdomain matching 'somesubdomain'
constrain :subdomain => /^somesubdomain/ do
root to: 'blog#show'
resources :foobars
end
Another approach would be to define the constraint match in a class (or module) and then wrap all routes within constraints block:
class WorldWideWebSubdomainConstraint
def self.matches?(request)
request.subdomain.present? && request.subdomain != 'www'
end
end
App::Application.routes.draw do
# All "www" requests handled here
constraints(WorldWideWebSubdomainConstraint.new) do
root to: 'session#new'
resources :foobars
end
# All non "www" requests handled here
root to: 'blogs#show', via: [:get, :post]
end

Overwrite root route in rails 4 for a certain subdomain

I'd like so overwrite my root :to => redirect("/projects") route if the subdomain is equal to "www" or is just "". This means if the subdomain is "www" or "" the app should use my website#index controller/action.
At the moment I got this setup:
class Subdomain
def self.match(r)
r.subdomain == "www" || r.subdomain == ""
end
end
.....
# website
scope :constraints => lambda { |request| Subdomain.match(request) } do
get '/' => 'website#index'
get "/help" => "website#help", as: "help"
get "/about" => "website#about", as: "about"
get "/signup" => "website#signup", as: "signup"
# post "/signup" => "website#signup_account"
end
root :to => redirect("/projects")
If I access www.satisfy.dev/help or satisfy.dev/help everything works fine. If I access www.satisfy.dev/ or satisfy.dev/ the root_path (/projects) is in use. I thought the get '/' => 'website#index' should be more important than the root_path since it's above the root_path.
Hope somebody has a hint for me!
I tried treating the routes as "get" requests and had more success.
See here:
Multiple 'root to' routes in rails 4.0

Rails 3 - Subdomain Issue Moving to Heroku

I've written an application that uses a subdomain per user account to segregate environments. All this is working fine, except I have one issue. I can't get both www and "" to have a different root path than all other subdomains.
For all account subdomains, I have a root page of:
root :to => "applications#index"
I need this to be the root page for all subdomains except for a blank subdomain of "" and then "www". For www, I have this in the routes:
constraints(:subdomain => "www") do
root :to => "promos#index"
end
What I'm struggling with, is getting it so "" will also use promos#index as the root path. When it's not the root path, mywebsite.com sends them to the applications#index, which requires a login. Something I don't want users to see on a first visit.
Is there anyway to modify this code to also include mywebsite.com to have the different root? I've tried things like duplicating the code with "", but this tends to mess up all other subdomains, regardless of order. Below is the in of my routes file:
constraints(:subdomain => "www") do
root :to => "promos#index"
end
root :to => "applications#index"
You can use an object that implements 'matches?' to do some real custom stuff. Below we'll set applications#index if you are a customer subdomain, and send you to promo#index if you're not
In your routes:
Yourapp::Application.routes.draw do
constraints(SubDomain) do
root :to => "applications#index"
end
root :to => "promo#index"
...
end
and then the Subdomain matcher file:
config/initializers/subdomain.rb
class SubDomain
def self.matches?(request)
case request.subdomain
when 'www', '', nil, #admin/api/etc could also go here
false
else
true
end
end
end
subdomain.rb can also live in lib (if it's being auto-loaded)

Issues with using subdomains with Cucumber/Capybara

I have successfully added the ability to use dynamic subdomains within my application. The issue is that when I run my Cucumber tests, I receive the following error when my application performs a redirect_to which contains a subdomain:
features/step_definitions/web_steps.rb:27
the scheme http does not accept registry part: test_url.example.com (or bad hostname?)
I have a signup controller action that creates the user and the account chosen and redirects the the user to the logout method with the subdomain specified based on what the user selected as the subdomain in the sign up form. Here is the code for the redirect action that happens once the user and account models are created and saved:
redirect_to :controller => "sessions", :action => "destroy", :subdomain => #account.site_address
Here are my rails 3 routes:
constraints(Subdomain) do
resources :sessions
match 'login', :to => 'sessions#new', :as => :login
match 'logout', :to => 'sessions#destroy', :as => :logout
match '/' => 'accounts#show'
end
Here is the code I have so far for the Subdomain class which is specified in the constraint above:
class Subdomain
def self.matches?(request)
request.subdomain.present? && request.subdomain != "www"
end
end
I added UrlHelper to the ApplicationController:
class ApplicationController < ActionController::Base
include UrlHelper
protect_from_forgery
end
This is the code for the above UrlHelper class:
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
All of this code above allows me to run subdomains fine within the local browser. The issue above happens when I run my Cucumber test. The test clicks the signup button which in turn calls the redirect_to and throws the exception listed above.
Here is what my gem file looks like:
require 'subdomain'
SomeApp::Application.routes.draw do
resources :accounts, :only => [:new, :create]
match 'signup', :to => 'accounts#new'
constraints(Subdomain) do
resources :sessions
match 'login', :to => 'sessions#new', :as => :login
match 'logout', :to => 'sessions#destroy', :as => :logout
match '/' => 'accounts#show'
end
end
Could you please let be know an additional method to have my tests work now? I would be interested in either a fix or a way I can test my methods without using subdomains (for example a mocked out method that retrieves the account name).
I have this same pattern in my code. I use Capybara (but not Cucumber), and I was able to get around it like this:
# user creates an account that will have a new subdomain
click_button "Get Started"
host! "testyco.myapp.com"
# user is now visiting app on new subdomain
visit "/register/get_started/" + Resetkey.first.resetkey
assert_contain("Get Started Guide")
The host! command effectively changes the host as it appears to the app from the test request.
EDIT: Just realized this was working with webrat, but not capybara (i'm using both, phasing out webrat now.) The way I'm doing it in capybara is to either click a link to a new domain (capybara follows it) or to:
visit "http://testyco.myapp.com/register"
EDIT: Another update. Found a method that works without having to use the full URL in every event.
host! "test.hiringthing.com"
Capybara.app_host = "http://test.hiringthing.com"
In the test setup.

Resources