Separate Domain for Namespaced Routes in Rails 4 - ruby-on-rails

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')

Related

Set a Rails route in an initializer

I'm building a web app with Ruby on Rails and I want a route to be user-editable. So I though of adding a simple initializer to add the route the user specified, but I don't really know how can I do this. Is there some easy way of doing it? I tried this on application.rb:
config.after_initialize do
Rails.application.reload_routes!
Rails.logger.info "#{Rails.application.routes.routes.map(&:path)}"
MyApp::Application.routes.draw do
get '/droplet' => 'admin#index'
end
end
But that doesn't seems to work. This is what I have in my routes.rb:
MyApp::Application.routes.draw do
devise_for :users
root :to => 'target_finder#show_page'
match '*path' => 'target_finder#show_page'
end
Thanks in advance!
How about making a controller action that takes in the params, tests to see if they match the configured route, and take action from there.
MyApp::Application.routes.draw do
devise_for :users
root :to => 'target_finder#show_page'
match '*path' => 'test_if_custom#CustomController'
end
class CustomController < ActionController::Base
def test_if_custom
if url_for(params) == Rails.application.routes.routes.map(&:path)
take_custom_action
else
take_default_action # Redirects or errors, maybe.
end
end
end
I suggest having a look at the friendly_id gem, which can define custom routes from any attribute of the user, so you could have a :url user attribute and then use that for the route by adding a slug index and then putting extend FriendlyId and friendly_id :url, use: :slugged in the user model.

Rails 3.2 routing error with scope

This problem has taken all day of mine...
Well;
I'm just trying to put all of my administration pages inside an /admin directory and to receive them via domain/admin style only. I've tried to make it run with this guide.
According to that official guide, what I'm looking for is using scope in my routes.rb file. BECAUSE, I have used named routes tones of times inside my pages. I do not want my program_path named route to change admin_program_path since I have 28 different usage of it.
So I'm supposed to use scope instead of namespace.
Issue is: I can not make scope work with my project.
Here is my routes.rb
scope "/admin" do
get "access/login"
get "access/index"
match "access/login_attempt", to: "access#login_attempt"
match "access/logout", to: "access#logout"
resources :admin_users
root to: 'programs#index'
resources :programs
resources :program_categories
resources :program_subcategories
resources :articles
resources :pictures
match '/kategoriler/:id' => 'program_categories#show'
match '/kategoriler' => 'program_categories#index'
match '/kategori/yeni' => 'program_categories#new'
match 'program/yeni' => 'programs#new'
match 'programlar' => 'programs#index'
match '/progam_categories/select_category/:program_id' => 'program_categories#select_category'
match '/program_subcategories/select_subcategory' => 'program_subcategories#select_subcategory'
match '/program_subcategory/add_subcategory' => 'program_subcategories#add_subcategory'
end
Here is my controller beginning :
class ProgramsController < ApplicationController
Just like told here:
If you want to route /admin/posts to PostsController (without the Admin:: module prefix), you could use
scope "/admin" do
resources :posts, :comments
end
As a result, what am I getting?
This error message:
Routing Error
uninitialized constant ProgramsController
Whichever controller I try to access, error changes that way.. Such like uninitialized constant ProgramCategoriesController , uninitialized constant ProgramSubcategoriesController etc...
I've tried to place application_controller both inside admin folder and root of controllers directory... No way.
Where is my mistake here? :(
Thanks in advance...
Try with :module parameter:
scope '/admin', :module => 'admin' do
# ...
end
The assumption is that your controllers are in Admin module namespace, so they start with 'Admin::'.
[EDIT]
It is response to your problem in comments below about path conflicts. You can use :as parameter, for example:
scope '/admin', :module => 'admin', :as => 'admin' do
# ...
end
You can check it with rake routes. All routes in the admin scope should now begin with 'admin_'

Not able to route using after_inactive_sign_up_path_for

I overridden RegistrationController my_devise/Registration controller
i overridden the following methos:
def after_inactive_sign_up_path_for(resource)
awaiting_confirmation_path
end
I also have a new method in my RegistrationController named:
def awaiting_confirmation(resource)
do tuff....
end
My routing file looks likethis:
devise_for :accounts, :controllers => {
:registrations => "my_devise/registrations"}
resources :registration do
match "awaiting_confirmation" => "registrations#awaiting_confirmation"
end
I get an error message:
No route matches {:action=>"awaiting_confirmation", :controller=>"registrations"}
What am i doing wrong?
resources :registration do
match "awaiting_confirmation" => "registrations#awaiting_confirmation"
end
Where are you specifying that your registrations controller is in my_devise folder??
You need to specify that manually, because Rails follows conventions, and therefore its looking in the app/controllers directory to find the registrations controller, that you have written yourself.
To get more idea about this, have a look at the output of rake routes command and find the route that rails has generated for it.

Rails Restful Routing and Subdomains

I wondered if there were any plugins or methods which allow me to convert resource routes which allow me to place the controller name as a subdomain.
Examples:
map.resources :users
map.resource :account
map.resources :blog
...
example.com/users/mark
example.com/account
example.com/blog/subject
example.com/blog/subject/edit
...
#becomes
users.example.com/mark
account.example.com
blog.example.com/subject
blog.example.com/subject/edit
...
I realise I can do this with named routes but wondered if there were some way to keep my currently succinct routes.rb file.
I think that subdomain-fu plugin is exacly what you need.
With it you will be able to generate routes like
map.resources :universities,
:controller => 'education_universities',
:only => [:index, :show],
:collection => {
:all => :get,
:search => :post
},
:conditions => {:subdomain => 'education'}
This will generate the following:
education.<your_site>.<your_domain>/universities GET
education.<your_site>.<your_domain>/universities/:id GET
education.<your_site>.<your_domain>/universities/all GET
education.<your_site>.<your_domain>/universities/search POST
The best way to do it is to write a simple rack middleware library that rewrites the request headers so that your rails app gets the url you expect but from the user's point of view the url doesn't change. This way you don't have to make any changes to your rails app (or the routes file)
For example the rack lib would rewrite: users.example.com => example.com/users
This gem should do exactly that for you: http://github.com/jtrupiano/rack-rewrite
UPDATED WITH CODE EXAMPLE
Note: this is quickly written, totally untested, but should set you on the right path. Also, I haven't checked out the rack-rewrite gem, which might make this even simpler
# your rack middleware lib. stick this in you lib dir
class RewriteSubdomainToPath
def initialize(app)
#app = app
end
def call(env)
original_host = env['SERVER_NAME']
subdomain = get_subdomain(original_host)
if subdomain
new_host = get_domain(original_host)
env['PATH_INFO'] = [subdomain, env['PATH_INFO']].join('/')
env['HTTP_X_FORWARDED_HOST'] = [original_host, new_host].join(', ')
logger.info("Reroute: mapped #{original_host} => #{new_host}") if defined?(Rails.logger)
end
#app.call(env)
end
def get_subdomain
# code to find a subdomain. simple regex is probably find, but you might need to handle
# different TLD lengths for example .co.uk
# google this, there are lots of examples
end
def get_domain
# get the domain without the subdomain. same comments as above
end
end
# then in an initializer
Rails.application.config.middleware.use RewriteSubdomainToPath
This is possible without using plugins.
Given the directory structure app/controllers/portal/customers_controller.rb
And I want to be able to call URL helpers prefixed with portal, i.e new_portal_customer_url.
And the URL will only be accessible via http://portal.domain.com/customers.
Then... use this:
constraints :subdomain => 'portal' do
scope :module => 'portal', :as => 'portal', :subdomain => 'portal' do
resources :customers
end
end
As ileitch mentioned you can do this without extra gems it's really simple actually.
I have a standard fresh rails app with a fresh user scaffold and a dashboard controller for my admin so I just go:
constraints :subdomain => 'admin' do
scope :subdomain => 'admin' do
resources :users
root :to => "dashboard#index"
end
end
So this goes from this:
site.com/users
to this :
admin.site.com/users
you can include another root :to => "{controller}#{action}" outside of that constraint and scope for site.com which could be say a pages controller. That would get you this:
constraints :subdomain => 'admin' do
scope :subdomain => 'admin' do
resources :users
root :to => "dashboard#index"
end
end
root :to => "pages#index"
This will then resolve:
site.com
admin.site.com
admin.site.com/users
Ryan Bates covers this in his Railscast, Subdomains.

constraints in ruby-on-rails routing

Could someone describe what this is all about?
It's in the routing file:
match "photo", :constraints => {:subdomain => "admin"}
I can't understand it.
thanks
It's saying that the photo route will only be recognised and routed to a controller if the request contains the subdomain admin. For example, the Rails application would respond to a request of http://admin.example.org/photo, but not http://example.org/photo.
One our guys posted this today which describes how you could reuse the same routes with different contexts (in this case whether the user is logged in)
For instance if you create a simple class to evaluate true/false:
class LoggedInConstraint < Struct.new(:value)
def matches?(request)
request.cookies.key?("user_token") == value
end
end
You can then use the evaluator in the routes to determine what routes apply:
root :to => "static#home", :constraints => LoggedInConstraint.new(false)
root :to => "users#show", :constraints => LoggedInConstraint.new(true)
Obviously you can design the constraints to your needs, but Steve described a couple different variants.

Resources