Rails: Routing subdomain to a resource - ruby-on-rails

Is it possible to map a subdomain to a resource? I have a company model. Currently, using subdomain_fu, my routing file contains:
map.company_root '', :controller => 'companies', :action => 'show',
:conditions => { :subdomain => /.+/ }
My Company model contains a "subdomain" column.
Whilst this works as intended, it's a named route and isn't restful. Essentially, I need to map "name.domain.com" to the show action for the companies controller. Is a named route the way to go, or can I use a resource route?

One can pass conditions to a resource route as well as a named route. In an application I am involved with everything is scoped to an account. A :before_filter loads the account using the subdomain. Thus for resources scoped to an account, we want to scope the routes to urls with subdomains. The DRY way to do this is to use map with options:
map.with_options :conditions => {:subdomain => /.+/} do |site|
site.resources :user_sessions, :only => [:new, :create, :destroy]
site.resources :users
site.login 'login', :controller => "user_sessions", :action => "new"
site.logout 'logout', :controller => "user_sessions", :action => "destroy"
…
end
map.connect 'accounts/new/:plan', :controller => "accounts", :action => "new"
map.resources :accounts, :only => [:new, :create]
As you can see a named route will accept a conditions hash with a subdomain too. You can also adopt the approach Ryan illustrated above or you can specify conditions on a per resource basis:
map.resources :users, :conditions => {:subdomain => /.+/}

I don't know of a way to do this with map.resources. It does accept a :conditions option but I'm not sure how to remove the /companies/ portion of the URL. However, map.resources is primarily a convenient way to generate a bunch of named routes, which you can do manually. Something like this.
map.company '', :controller => 'companies', :action => 'show', :conditions => { :subdomain => /.+/, :method => :get }
map.new_company 'new', :controller => 'companies', :action => 'new', :conditions => { :subdomain => /.+/, :method => :get }
map.edit_company 'edit', :controller => 'companies', :action => 'edit', :conditions => { :subdomain => /.+/, :method => :get }
map.connect '', :controller => 'companies', :action => 'create', :conditions => { :subdomain => /.+/, :method => :post }
map.connect '', :controller => 'companies', :action => 'update', :conditions => { :subdomain => /.+/, :method => :put }
map.connect '', :controller => 'companies', :action => 'destroy', :conditions => { :subdomain => /.+/, :method => :delete }
Untested, but it should get you close.

Here's a complete example implementation of Rails 3 subdomains with authentication (along with a detailed tutorial). It's much easier to do this in Rails 3 than in Rails 2 (no plugin required).

Using the resource linked from Daniel's answer, in Rails 3 the way to route '/' to a different controller depending on the subdomain is as follows:
match '/' => 'somecontroller#action', :constraints => { :subdomain => 'yoursubdomain' }

Related

How to routes to a specific controller with a variable value ahead of it in rails 5?

Normally its like:
resources :users
To keep a value ahead we can do like
scope :url do
resources :users
end
but, issue is that I have the just variable in front of the routes not a fixed value with few conditions for it.
Example in rails 2. and want to convert the routing accoding to rails5
map.with_options :controller => 'users' do |user|
user.forgot_user ':url/users/forgot', :action => 'forgot', :url => /([a-zA-Z0-9\-]*)/
user.user ':url/users/retrieve', :action => 'retrieve', :url => /([a-zA-Z0-9\-]*)/
user.login ':url/users/login', :action => 'login', :url => /([a-zA-Z0-9\-]*)/
user.logout ':url/users/logout', :action => 'logout', :url => /([a-zA-Z0-9\-]*)/
user.new_user ':url/users/new', :action => 'new', :conditions => { :method => :get }, :url => /([a-zA-Z0-9\-]*)/
user.users ':url/users/:id', :action => 'show', :conditions => { :method => :get }, :url => /([a-zA-Z0-9\-]*)/
end
Thanks in advance.
scope "/(:subdomain)", :defaults => {:subdomain => "default"} do
...
end
use subdomain as a variable.

How to implement different http method match different action with the url defined by myself based on Rails` REST

Now,I have:
map.resources :questions, :collection => {
:query_by_student => :get
}
that matches:
query_by_student_questions GET /questions/query_by_student(.:format)
{:controller=>"questions", :action=>"query_by_student"}
I want add a "POST" request,to the same url:/questions/query_by_student,but the action should be "post_by_student"
waht shall I do?
怎么在Rails的REST基础上对自己定义的url,实现不同http方法对应不同action?
我现在有这:
map.resources :questions, :collection => {
:query_by_student => :get
}
对应路由信息:
query_by_student_questions GET /questions/query_by_student(.:format)
{:controller=>"questions", :action=>"query_by_student"}
我想加一个post请求,同样到/questions/query_by_student,但是action为post_by_student
怎么写?
I don't have a testing app but with rails 2.2, you can try
map.resources :questions, :collection => {
:query_by_student => [:get, :post]
}
and see what it looks like.
Otherwise, you can probably do it manually with something like
map.connect '/questions/query_by_student', :conditions => { :method => :get }, :controller => 'questions', :action => 'query_by_student'
map.connect '/questions/query_by_student', :conditions => { :method => :post }, :controller => 'questions', :action => 'post_by_student'

Is there a better way to do with_options in Rails 3 routes?

Here are my Rails 2 routes:
map.with_options :controller => 'foo', :conditions => { :method => :post } do |foo|
foo.one 'one', :action => 'one'
foo.two 'two', :action => 'two'
foo.with_options :special_flag => 'true', :path_prefix => 'special_prefix',
:conditions => { :method => :get } do |bar|
bar.three '', :action => 'for_blank'
bar.four 'another', :action => 'for_another'
end
end
How do I convert this sort of thing to Rails 3? Just keep using with_options in the same way? It becomes wordier in some cases because instead of doing
match '' => 'foo#for_blank'
I'm doing
match '', :action => 'for_blank'
Yeah, with_options still works in Rails 3. Try this out:
map.with_options :controller => 'foo', :via => :post do
match 'one', :action => 'one' #automatically generates one_* helpers
match 'two', :action => 'two' #automatically generates two_* helpers
foo.with_options :special_flag => 'true', :path => 'special_prefix', :via => :get do
match '', :action => 'for_blank'
match 'another', :action => 'for_another', :as => "four" # as will change the helper methods names
end
end
The :via option replaces your ugly conditions hash with a much nicer syntax.
Like this:
#JSON API
defaults :format => 'json' do
get "log_out" => "sessions#destroy", :as => "log_out"
get "log_in" => "sessions#new", :as => "log_in"
get "sign_up" => "users#new", :as => "sign_up"
resources :users, :sessions
end
Try to stick to the methods the routes provide. They are very powerful in Rails 3 and should provide everything you need. See http://guides.rubyonrails.org/routing.html for more details

Rails: Mapping Conflicting Routes by Detecting Param

Hey! I am trying to set up routes in a Rails application so that, depending on the type of parameter passed, Rails sends the request to a different action.
I have courses which have an attribute state which is a string with a two letter state abbreviation. When a user visits /courses/1, I want Rails to display the show action in the courses controller (and pass the parameter as :id). When a user visits /courses/CO though, I want Rails to display the index action and pass the parameter as :state.
So /courses/1 would be equivalent to
:controller => 'courses', :action => 'show', :id => '1'
And /courses/CO would be equivalent to
:controller => 'courses', :action => 'index', :state => 'CO'
I have tried this:
map.resources :courses, :except => { :index, :show }
map.connect 'courses/:state', :controller => 'courses', :action => 'index', :state => /[A-Z]{2}/
map.connect 'courses/:id', :controller => 'courses', :action => 'show', :id => /[0-9]+/
But it breaks (the rails server wont even start). I don't usually do things like this with routes, so I am outside of my know-how. Thanks!
Edit: Fixed a typo, thanks JC.
Current solution looks like this:
map.resources :courses, :except => [ :index, :show ]
map.courses '/courses', :controller => 'courses', :action => 'index', :state => 'AL', :method => :get
map.courses '/courses/:state', :controller => 'courses', :action => 'index', :requirements => { :state => /[A-Z]{2}/ }, :method => :get
map.course '/courses/:id', :controller => 'courses', :action => 'show', :requirements => { :id => /[0-9]+/ }, :method => :get
This works, but you will need to go edit all your links to the index to say things like courses_path('AA') and you won't be able to use some of the nice helpers, like form_for, which assume you are following the convention that #create is simply #index with a POST request. (Get comfortable with form_tag)
ActionController::Routing::Routes.draw do |map|
map.resources :courses, :except => [ :index, :show ]
map.courses '/courses/:state', :controller => 'courses', :action => 'index', :requirements => { :state => /[A-Z]{2}/ } , :method => :get
map.course '/courses/:id', :controller => 'courses', :action => 'show', :requirements => { :id => /[0-9]+/ } , :method => :get
end
It will keep your routes named the same, though.
(by the way, your /co does not match your regex, which requires upper case chars)
Fun aside: Do we really need the abstraction of a router? http://blog.peepcode.com/tutorials/2010/rethinking-rails-3-routes
I'm afraid this won't work since the structure that maps paths to controllers and actions is setup on start of the rails application, parameter handling happens at request time.
What you could do is to match the :id-parameter in the show-action of the CoursesController against a list of valid states and then either redirect or render a different action.
Hope this helps.

Custom dynamic error pages in Ruby on Rails not working

I'm trying to implement custom dynamic error pages following this post:
http://www.perfectline.co.uk/blog/custom-dynamic-error-pages-in-ruby-on-rails
I did exactly what the blog post says. I included config.action_controller.consider_all_requests_local = false in my environment.rb. But is not working.
My browser shows:
Routing Error
No route matches "/555" with {:method=>:get}
So, it looks like the rescues are not fired.
I get the following in my log file:
ActionController::RoutingError (No route matches "/555" with {:method=>:get}):
Rendering rescues/layout (not_found)
Is there some routing interfering with the code? I'm not sure what to look for. I'm running rails 2.3.5.
Here is the routes.rb file:
ActionController::Routing::Routes.draw do |map|
# routing van property-url
map.connect 'buy/:property_type_plural/:province/:city/:address/:house_number', :controller => 'properties' , :action => 'show', :id => 'whatever'
map.myimmonatie 'myimmonatie' , :controller => 'myimmonatie/properties', :action => 'index'
map.login "login", :controller => "user_sessions", :action => "create", :conditions => {:method => :post}
map.login "login", :controller => "user_sessions", :action => "new"
map.logout "logout", :controller => "user_sessions", :action => "destroy"
map.buy "buy", :controller => 'buy'
map.sell "sell", :controller => 'sell'
map.home "home", :controller => 'home'
map.disclaimer "disclaimer", :controller => 'disclaimer'
map.sign_up "sign_up", :controller => 'users', :action => :new
map.contact "contact", :controller => 'contact'
map.resources :user_sessions
map.resources :contact
map.resources :password_resets
map.resources :messages
map.resources :users, :only => [:index,:new,:create,:activate,:edit,:profile,:password]
map.resources :images
map.resources :activation , :only => [:new,:resend]
map.resources :email
map.resources :properties, :except => [:index,:destroy]
map.namespace :admin do |admin|
admin.resources :users
admin.resources :properties
admin.resources :order_items, :as => :orders
admin.resources :blog_posts, :as => :blog
end
map.connect 'myimmonatie/:action' , :controller => 'users', :id => 'current', :requirements => {:action => /(profile)|(password)|(email)/}
map.namespace :myimmonatie do |myimmonatie|
myimmonatie.resources :messages, :controller => 'messages'
myimmonatie.resources :password, :as => "password", :controller => 'users', :action => 'password'
myimmonatie.resources :properties , :controller => 'properties'
myimmonatie.resources :orders , :only => [:index,:show,:create,:new]
end
map.root :controller => "home"
map.connect ':controller/:action'
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
end
ActionController::Routing::Translator.translate_from_file('config','i18n-routes.yml')
The code works, something is wrong with the line in my environment.rb
config.action_controller.consider_all_requests_local = false
It seems to be overridden somewhere.
So, CASE CLOSED, thanks!
Rails detects when you are browsing with ip 127.0.0.1 and shows you the development environment errors even if you are in production environment. You should try accessing from a different machine to get the proper errors.

Resources