Exclude all other resources from subdomain in Rails - ruby-on-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

Related

allow access to one page on sub-domain, and if tried accessing other pages redirect to main domain

allow access to one page(campaigns/test) on sub-domain(aap.example.com), and if tried accessing other pages redirect to main domain(example.com)
app.example.com is my sub-domain of my main domain example.com, so same rails app is running on domain and sub-domain.
I tried some solutions like adding constraints in routes file and nginx file as well, but not getting what I need.
routes.rb
constraints(Subdomain) do
match '/campaigns/:slug' => 'campaigns#show', via: [:get]
match "/cam_enquiry" => "campaigns#cam_enquiry", via: [:post]
end
and the subdomain.rb module
class Subdomain
def self.matches?(request)
case request.subdomain
when 'app', '', nil
false
else
true
end
end
end
Let me know if you need anymore details.
Define all your routes and after it define constraint for app subdomain. You need to match test route and use redirect for all other subdomain routes. Specify only blank subdomain in redirect parameters, in this case it will get all other info from request and only change subdomain to main domain
get 'campaigns/test', to: redirect(subdomain: 'app'), constraints: { subdomain: '' }
get '/campaigns/:slug', to: 'campaigns#show'
post '/cam_enquiry', to: 'campaigns#cam_enquiry'
constraints subdomain: 'app' do
get 'campaigns/test', to: 'contoroller#action'
get '/*any', to: redirect(subdomain: '')
end

Do not match routes outside of subdomain constraint for requests in that subdomain

From routes.rb:
constraints subdomain: 'admin' do
scope module: 'admin', as: 'admin' do
resources :subscribers
root 'dashboard#index'
end
end
resources :users
root 'dashboard#index'
Under current snippet GET admin.domain.xzy/users still triggers users controller action. I understand that the rules will continue to be parsed until one specifies. Is there a way to modify this behavior? Such that for the subdomain constraint, the router will only search within that block.
Why not put the offending line inside another constraint?
constraints(NoSubdomain) do
resources :users
end
The constraint would look something like this:
class NoSubdomain
def self.matches?(request)
!request.subdomain.present?
end
end

Subdomain based resources in Rails

I am looking for a simple way to replace all my routes matching mydomain.com/resources/xx by xx.mydomain.com with Rails 4.
Would anyone have an idea to do that easily and that would work with nested resources as well?
Thanks, Joris
Constraints
What you're looking for is constraints in your routes, specifically that you're looking to use one to determine whether you have a subdomain that you can access
There are a number of resources on how to achieve this:
Basecamp-style subdomains by DHH
Subdomains Railscast
The bottom line is that you'll probably have to create a custom subdomai constraint, which you can then use the standard routing structure for:
#lib/subdomain.rb
class Subdomain
def self.matches?(request)
if request.subdomain.present? && request.subdomain != 'www'
account = Account.find_by username: request.subdomain
return true if account # -> if account is not found, return false (IE no route)
end
end
end
#config/routes.rb
constraints(Subdomain) do
get "/", to: "controller#action"
resources :posts #-> subdomain.domain.com/posts
...
end
The above is untested - I also found the following with Rails' documentation:
#lib/subdomain.rb
class Subdomain
def initialize
#accounts = Account.all
end
def matches?(request)
if request.subdomain.present? && request.subdomain != 'www'
#accounts.include?(request.subdomain)
end
end
end
#config/routes.rb
constraints: Subdomain.new do
get "/", to: "controller#action"
resources :posts #-> subdomain.domain.com/posts
...
end
Here how I have done it before in a Rails 3 app:
constraints :subdomain => /ambassador/ do
namespace(:influencer, :path => '/') do
root :to => 'home#index'
match 'home' => 'sweepstakes#index', :as => :influencer_home
resources :sweepstakes
resources :associates
resources :widgets
resources :sessions
resources :reports do
resource :member
end
match 'faq' => 'info#faq'
end
end
Be sure to put this block towards the top of the routes.rb file so it takes precedence.
You can of course nest your resources in here like normal.

Rails namespace admin on custom subdomain

My rails app is set to use subdomains as described in this RailsCast:
http://railscasts.com/episodes/221-subdomains-in-rails-3
Now, I would like to add an admin subdomain to the front of my blog subdomain as follows:
admin.company.lvh.me:3000
I've tried to namespace admin outside of my Subdomain constraint:
namespace :admin, path: '/', constraints: { subdomain: 'admin' } do
constraints(Subdomain) do
match '/', to: 'blogs#show', via: 'get'
end
end
But instead of routing through my app/controllers/admin/blogs_controller it attempts to route through my "normal user" controller (app/controllers/blogs_controller).
Am I just missing something simple or is doing something like this in rails much more difficult?
I was able to solve this, although it feels a little hackish. Understanding that Rails treats constraints either true or false, I set another constraint inside the initial subdomain constraint check. It splits the subdomain in 2 and examines the first subdomain to see if it equals "admin". If true, it routes to the admin/controllers and admin/views (because of module: "admin"), if not, it routes to the less specific routes that are not inside the "admin" module.
At first I didn't have the namespace :admin, and my route helpers were incorrect (the admin routes weren't prefixed with "admin" and the less specific routes weren't being set since they were duplicates). Once I added namespace :admin and the path: "" (this is important, too, because it removes "admin/" from the URI Pattern), it worked!
One last thing, in the admin/controllers, you have to edit the set_blog method, since "admin.company" is being interpreted instead (see admin/blogs_controller.rb).
routes.rb
Blog::Application.routes.draw do
constraints(Subdomain) do
namespace :admin, module: "admin", path: "", constraints: lamda { |r| r.subdomain.split('.')[0] == 'admin' } do
match '/', to: 'blogs#show', via: 'get'
...
end
match '/', to: 'blogs#show', via: 'get'
...
end
...
end
Rake Routes:
Prefix Verb URI Pattern Controller#Action
admin GET / admin/blogs#show
...
​ GET / blogs#show
...
admin/blogs_controller.rb
BlogController < ApplicationController
before_action :set_blog
...
private
set_blog
#blog = Blog.find_by_subdomain!(request.subdomain.split('.')[1])
end
end
Let me know if there's anything cleaner out there, if not, hopefully this helps others with this issue.
There are several important factors here
Firstly, you'll need to see what the constraint params look like with "multi" subdomains. Instead of splitting, Rails may have admin.company as the subdomain
If we take the idea that Rails will split the subdomains into two, which one is being called as the "parent"?
namespace :admin, path: '/', constraints: { subdomain: 'admin' } do
constraints(Subdomain) do
resources :blogs, only: :show, path_names: { show: "" }
end
end
If you give us some more info on the request (params etc), we'll be in a much better position to help!

Rails 3.1 Multitenancy routes

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

Resources