Prevent subdomain access for html requests - ruby-on-rails

I have a subdomain widgets.mywebsite.com. The only thing the subdomain does is return json on a given route. How do I prevent people/crawlers accessing my site via the subdomain whilst still keeping the route available? I would be happy to simply redirect any requests that include this subdomain to mywebsite.com but can't work out how to do it.
constraints :subdomain => 'widgets' do
namespace :widgets, :path => nil, :format => 'json' do
match 'v1' => 'v1/widgets#index'
end
end

So it sounds like you want to reverse the logic in your routes - you want to constrain the bulk of your routes so that they only resolve when the subdomain isn't equal to widgets. That's opposed to the above example, where you're making a single route only available on the 'widgets' subdomain. This is pretty straightforward.
In your config/routes.rb you can define a class before the Application.routes.draw block
class NotWidgetsRequest
def matches?(request)
request.subdomain != 'widgets'
end
end
and then you can wrap all of your routes other than the v1/widgets#index route in a
constraints NotWidgetRequest.new do
...
end
block. This will prevent these routes from resolving on widgets.mywebsite.com

Related

Rails wildcard route with database lookup & multiple controllers

I have a Rails application setup where, after all of the other site routes are defined, I have a catch-all wildcard for my Users to display their Profiles on selected root-level "vanity" URLs of non-reserved paths/keywords:
get '*path' => 'profiles#show'
The Profiles controller then checks to make sure the path defines a valid Profile, otherwise redirects to root. This works fine.
What I need to do now is create a mechanism where the catch-all path could define either a Profile or a Blog, based on the database lookup of the path for the proper controller to route to.
I do not want to do a redirect ... I want to load either the Profile or Blog content on the original wildcard URL.
What are my options to go from wildcard route -> db lookup -> proper controller?
In other words, where might this logic properly go?
Thanks.
It seem like you want a route constraint that will match some pattern (regex) that defines if a path matches a route or if it tries the subsequent routes. Maybe something like this.
get '*path', :to => 'profiles#show', :constraints => { path: /blog\/.+/ }
The idea is that you must know something at the routing level, if it can be path based then the above thing will work otherwise if it needs to be more complex you can use a custom constraints class.
# lib/blog_constraint.rb
class BlogConstraint
def initialize
#slugs = Blog.pluck(:slug)
end
def matches?(request)
request.url =~ /blog\/(.+)/
#slugs.include?($1)
end
end
# config/routes.rb
YourApp::Application.routes.draw do
get '*path', :to => 'blogs#show', :constraints => BlogConstraint.new
get '*path', :to => 'profiles#show'
end

Ruby on Rails route for wildcard subdomains to a controller/action

I dynamically create URLs of the form username.users.example.com:
bob.users.example.com
tim.users.example.com
scott.users.example.com
All of *.users.example.com requests should go to a particular controller/action. How do I specify this in routes.rb?
All other requests to www.example.com go to the normal list of routes in my routes.rb file.
UPDATE: I watch the railscast about subdomains and it showed the following bit of code which would seem to be exactly what I need (changed the controller and subdomain):
match '', to: 'my_controller#show', constraints: {subdomain: /.+\.users/}
The problem is it only matches the root URL. I need this to match EVERY possible URL with a *.users subdomain. So obviously I would put it at the top of my routes.rb file. But how do I specify a catch-all route? Is it simply '*'? Or '/*'?
I think, you just need to do the following :
create a class Subdomain in lib :
class Subdomain
def self.matches?(request)
request.subdomain.present? && request.host.include?('.users')
end
end
and in your routes :
constraints Subdomain do
match '', to: 'my_controller#show'
end
You can constraint route dynamically based on some specific criteria by creating a matches? method
Lets say we have to filter sub domain of URL
constraints Subdomain do
get '*path', to: 'users#show'
end
class Subdomain
def self.matches?(request)
(request.subdomain.present? && request.subdomain.start_with?('.users')
end
end
What we are doing here is checking for URL if it start with sub domain users then only hit users#show action. Your class must have mathes? method either class method or instance method. If you want to make it a instance method then do
constraints Subdomain.new do
get '*path', to: 'proxy#index'
end
you can achieve same thing using lambda as well like below.
Instead of writing class we can also use lambdas
get '*path', to: 'users#show', constraints: lambda{|request|request.env['SERVER_NAME'].match('.users')}

Specify a route without subdomains

I'm running Rails 3.0.17.
I currently have the following defined in my routes:
constraints :subdomain => "" do
get 'faq' => 'static_pages#faq'
end
The problem is that it allows any faq url with a subdomain (e.g. anysubdomain.mypage.com/faq)to route to the faq page when I only want the url without a subdomain (mypage.com/faq) to route to the faq page.
Any tips/insights?
Thank you in advance.
In your routes.rb
constraints SubdomainConstraint.new do
get 'faq' => 'static_pages#faq'
end
In your lib/
class SubdomainConstraint
def self.matches?(request)
request.subdomain.blank?
end
end

Rails 3.2 - How to redirect to a namespace?

In a Rails 3.2 application I'm doing I want to create some views (and action handling) specific for mobile devices. So I have created a namespace called mobile.
namespace :mobile do
resources :sessions
resources :areas
end
For example if the user goes to the login page with a mobile I want to use the controller and views I make for that namespace.
So now I have two different ways to login:
new_mobile_session GET /mobile/sessions/new(.:format) mobile/sessions#new
and
new_session GET /sessions/new(.:format) sessions#new
But when a requests comes how could I add the "mobile" namespace to the request if it comes from mobile?
I.e. changing /sessions/new into /mobile/sessions/new
I am using Rack::MobileDetect but I don't know how to use the redirect_to for that purpose.
config.middleware.use Rack::MobileDetect, :redirect_to => '/mobile'
Or should I use a different approach?
Thanks.
You could use a constraint for that.
A Rails routing constraint either is class which responds to matches? or a lambda.
When a constraint is applied to a route, the route will only be considered if the constraint evaluates to true.
Consider this class
class MobileContraint
def matches? request
request.user_agent =~ /Mobile|webOS/
end
end
You can now use this class in the routes like this:
resources :sessions
resources :sessions, :controller=> 'mobile/sessions', :constraints => MobileConstraint.new

Force a route to exit a subdomain in Rails 3.2

I'm struggling with exiting out of a subdomain back up to the root domain in Rails 3.2.
Say I have a blog with a dashboard. Each user has a subdomain at username.blog.com. Each user also has a dashboard at blog.com/dashboard.
If a user manually types in username.blog.com/dashboard, I want them to be redirected to blog.com/dashboard.
I've tried using subdomain => false in my routes, but it seems to be of no use. I also tried a matcher underneath the domain scope, but that also didn't work. Any help would be greatly appreciated!
Relevant routes.rb follows.
resource :dashboard, :controller => 'dashboard', :subdomain => false
scope '/', constraints: lambda { |r| r.subdomain.present? && r.subdomain != 'www' } do
get '/' => 'feed#show'
end
root :to => 'dashboard#show', :subdomain => false
I would keep that logic outside the routing.
I would use dashboard_url instead of dashboard_path in my views / controllers.
I would put something like this in my ApplicationController
def dashboard_url(options={})
options[:subdomain] = false
super(options)
end

Resources