Setting up restful routes as a total newb - ruby-on-rails

I'm getting the following error:
Unknown action
No action responded to show. Actions: activate, destroy, index, org_deals, search, and suspend
Controller:
class Admin::HomepagesController < Admin::ApplicationController
def org_deals
#organization = Organization.find(:all)
end
Routes:
map.root :controller => 'main'
map.admin '/admin', :controller => 'admin/main'
map.namespace :admin do |admin|
admin.resources :organizations, :collection => {:search => :get}, :member => {:suspend => :get, :activate => :get}
To note: This is a controller inside of a controller.
Any idea why this is defaulting to show?
Update:
I updated what the routes syntax is. Read that article, and tried quite a few variations but its still adamantly looking for a show.

Firstly, it looks like your routes file has the wrong syntax. If you are trying to establish routes for nested resources, you'd do it like so:
map.resources :admin
admin.resources :organizations
end
This would give you paths such as:
/admin/
/admin/1
/admin/1/organizations
/admin/1/organizations/1
The mapping from route to controller/action is done via a Rails convention, where HTTP verbs are assigned in ways that are useful for the typical CRUD operations. For example:
/admin/1/organizations/1
would map to several actions in the OrganizationsController, distinguished by the type of verb:
/admin/1/organizations/1 # GET -> :action => :show
/admin/1/organizations/1 # PUT -> :action => :update
/admin/1/organizations/1 # DELETE -> :action => :destroy
"Show" is one of the seven standard resourceful actions that Rails gives you by default. You can exclude "show" with the directive :except => :show, or specify only the resourceful actions you want with :only => :update, for example.
I recommend you look at Rails Routing from the Outside In, which is a great introduction to this topic.
EDIT
I see I ignored the namespacing in my answer, sorry. How about this:
map.namespace(:admin) do |admin|
admin.resources :homepages, :member => { :org_deals => :get }
end
This will generate your org_deals action as a GET with an id parameter (for the organization). You also get a show route, along with the six other resourceful routes. rake routes shows this:
org_deals_admin_homepage GET /admin/homepages/:id/org_deals(.:format) {:controller=>"admin/homepages", :action=>"org_deals"}
Of course your homepages_controller.rb has to live in app/controllers/admin/
EDIT redux
Actually, you want organizations in the path, I'll bet, in which case:
map.namespace(:admin) do |admin|
admin.resources :organizations, :controller => :homepages, :member => { :org_deals => :get }
end
which gives you:
org_deals_admin_organization GET /admin/organizations/:id/org_deals(.:format) {:controller=>"admin/homepages", :action=>"org_deals"}

By specifying admin.resources ... you are telling Rails you want the seven default different routes in your application. If you do not want them, and only want the ones you specify, do not use .resources. Show is called because that's the default route called for a GET request with a path such as /admin/id when you have the default resources.

Related

Cleaning up Rails routes with non-restful actions

I have a subscriptions controller with routes that look like this:
get 'user/:user_id/subscription_requests' => 'subscriptions#index', as: :subscription_requests
post 'user/:user_id/subscribe' => 'subscriptions#subscribe', as: :user_subscribe
post 'user/:user_id/unsubscribe' => 'subscriptions#unsubscribe', as: :user_unsubscribe
post 'user/:user_id/request_subscription' => 'subscriptions#request_subscription', as: :request_user_subscription
post 'user/:user_id/accept_subscription' => 'subscriptions#accept', as: :accept_subscription_request
post 'user/:user_id/reject_subscription' => 'subscriptions#reject', as: :reject_subscription_request
All of them except index are non-restful actions. How do you make this cleaner in the routes file using something like resources while keeping the user/:user_id/ in the path?
Update for clarity:
I'm trying to avoid listing the routes line by line and instead do something like what rails provides with the restful actions. Something like:
resources :subscription_requests, :only => [:subscribe, :unsubscribe, :reject, :accept, etc]
You can use the member function of routing.
resources :user, to: 'subscriptions', :only => [] do
member do
get 'subscription_requests'
post 'subscribe'
etc
end
end
And this will produce routes such as:
subscription_requests_user GET /user/:id/subscription_requests(.:format) subscriptions#subscription_requests
subscribe_user POST /user/:id/subscribe(.:format) subscriptions#subscribe
Docs: http://guides.rubyonrails.org/routing.html#adding-more-restful-actions

ruby custom routes

I am new to ruby on rails.
Here is my routes.rb
RpxNowExample::Application.routes.draw do
root :to => "users#index"
resources :users
end
Normally my functionality is working fine, but I want to make a tweak. I want it to redirect to another view "promptemail" using the same controller calling another action if a condition is true i.e
if(#provider == "Twitter")
redirect_to :action => :promptemail
end
It should take me to that promptemail view.
You can pass a block to your resources definition to add extra actions outside of the standard:
resources :users do
match :promptemail, :via => [:get], :on => :member
end
The :via option allows you to restrict on get, post, put etc, the :on parameter will take either :member, or :collection.
:collection will operate on a collection, so similar to the index action, :member will operate on an individual record. As such if you specify your route as :on => :member, you will need to provide an object or id when you generate the route.
More info about adding routes to resources can be found here: http://guides.rubyonrails.org/routing.html#adding-more-restful-actions
Using the same controller calling another action-
Try:
routes.rb:
RpxNowExample::Application.routes.draw do
root :to => "users#index"
resources :users do
collection do
get 'promptemail'
end
Your controller:
if(#provider == "Twitter")
redirect_to :promptemail
end
Note: - No need to call action in redirect_to as you are calling the action within the same controller.

Rails 3 routes for single controller and multiple resources

I have multiple resources (:countries, :states, :schools etc.) but would like a single "Dashboard" controller to handle all the actions.
I would like to be able to do the following:
countries_path would direct me to a show_countries action in the DashboardController and be accesible by '/dashboard/countries.
Likewise for states, schools, etc.
I've read up on Rails routing and have been messing around with various options. I ended up with the following in my routes.rb file:
scope "toolbox" do
resources :countries, :controller => "toolbox", :only => :index do
get 'show_countries', :on => :collection
end
...
end
Running rake routes gives me the following for the code above:
show_countries_countries GET /toolbox/countries/show_countries(.:format) {:action=>"show_countries", :controller=>"toolbox"}
countries GET /toolbox/countries(.:format) {:action=>"index", :controller=>"toolbox"}
I've tried this:
scope "toolbox" do
resources :countries, :controller => "toolbox", :only => :index, :action => "show_countries"
end
only to get this route:
countries GET /toolbox/countries(.:format) {:action=>"index", :controller=>"toolbox"}
What I really want is this:
countries GET /toolbox/countries(.:format) {:action=>"show_countries", :controller=>"toolbox"}
Any ideas?
You just have to think outside of the 'resources' box:
scope "toolbox", :controller => :toolbox do
get 'countries' => :show_countries
get 'states' => :show_states
get 'schools' => :show_shools
end
Should output routes like this:
countries GET /toolbox/countries(.:format) toolbox#show_countries

Typus route order

It used to be that you could load Typus routes exactly where you needed them by placing
Typus::Routes.draw(map)
at the appropriate point in your routes.rb file. It seems that this is no longer supported and that they're always loaded after all of the application routes. This causes problems with catchall routes which must be defined last. Does anyone know how to control the load order for typus now? Is there a way to get them defined before any of the app routes rather than after? Thanks!
I got around it by leaving my catch-all routes at the end of my apps routes.rb BUT excluding it from matching for Typus urls:
# A catch all route
match '*path' => 'content#show', :constraints => lambda{|request|
!request.path.starts_with?("/admin") # excluded if typus will be taking it...
}
This may or may now work for you...
I'm looking for the same answer.
At the moment I have resorted to copying the contents from typus's config/routes.rb and placing it into my routes.rb file, before the catchall route.
It's a horrible, hackish solution, but it's solving my immediate problem.
Example:
# TODO: KLUDGE: MANUALLY BRING THE TYPUS ROUTES IN
# Typus used to provide :
# Typus::Routes.draw(map)
# But that is no longer the case.
scope "admin", :module => :admin, :as => "admin" do
match "/" => "dashboard#show", :as => "dashboard"
match "user_guide" => "base#user_guide"
if Typus.authentication == :session
resource :session, :only => [:new, :create, :destroy], :controller => :session
resources :account, :only => [:new, :create, :show, :forgot_password] do
collection do
get :forgot_password
post :send_password
end
end
end
Typus.models.map { |i| i.to_resource }.each do |resource|
match "#{resource}(/:action(/:id(.:format)))", :controller => resource
end
Typus.resources.map { |i| i.underscore }.each do |resource|
match "#{resource}(/:action(/:id(.:format)))", :controller => resource
end
end
# END KLUDGE
# Catch all to the state page handler
match '/:page' => 'pages#show', :as => 'page'

How to add a custom RESTful route to a Rails app?

I'm reading these two pages
resources
Adding more RESTful actions
The Rails Guides page shows
map.resources :photos, :new => { :upload => :post }
And its corresponding URL
/photos/upload
This looks wonderful.
My routes.rb shows this
map.resources :users, :new => { :signup => :get, :register => :post }
When I do: [~/my_app]$ rake routes
I see the two new routes added
signup_new_user GET /users/new/signup(.:format)
register_new_user POST /users/new/register(.:format)
Note the inclusion of /new! I don't want that. I just want /users/signup and /users/register (as described in the Rails Routing Guide).
Any help?
When you expose a controller as a resource, following actions are automatically added:
show
index
new
create
edit
update
destroy
These actions can be categorized in to two groups:
:member actions
The URL for the member action has the id of the target resource. E.g:
users/1/edit
users/1
You can think of :member action as an instance method on a class. It always applies on an existing resource.
Default member actions: show, edit, update, destroy
:collection actions
The URL for the :collection action does not contain the id of the target resource. E.g:
users/login
users/register
You can think of :collection action as a static method on a class.
Default collection actions: index, new, create
In your case you need two new actions for registration. These actions belong to :collection type( as you do not have the id of the user while submitting these actions). Your route can be as follows:
map.resources :users, :collection => { :signup => :get, :register => :post }
The URL for the actions are as follows:
users/signup
users/register
If you want to remove a standard action generated by Rails use :except/:only options:
map.resources :foo, :only => :show
map.resources :foo, :except => [:destroy, :show]
Edit 1
I usually treat the confirmation action as a :member action. In this case params[id] will contain the confirmation code.
Route configuration:
map.resources :users, :member => { :confirm => :get}
URL
/users/xab3454a/confirm
confirm_user_path(:id => #user.confirmation_code) # returns the URL above
Controller
class UsersController < ApplicationController
def confirm
# assuming you have an attribute called `confirmation_code` in `users` table
# and you have added a uniq index on the column!!
if User.find_by_confirmation_code(params[id])
# success
else
# error
end
end
end
This can be taken as just another syntax -- something good to know may be.
Syntax 1:
resources :users do
member do
get 'signup'
post 'register'
end
end
Rake Route Output will include
signup_users GET /users/signup(.:format) {:action=>"signup", :controller=>"users"}
register_users POST /users/register(.:format) {:action=>"register", :controller=>"use
rs"}
Syntax 2:
If you have only one collection route
resources :users do
get 'signup', :on => :collection
end
If i'm understanding your question right, you just want to rename the urls of the new and create actions.
This would be done like so:
map.resources :users, :path_names => {:new => 'signup', :create => 'register'}
If you really would like to add new routes with corresponding controller actions, then Damiens answer is the way to go.
The new option allows you to create new routes for creating new objects. That's why they're prefixed with that term.
What you're looking for is the :collection option.
map.resources :users, :collection => { :signup => :get, :register => :post }
Which will create the /users/signup and /users/register urls.

Resources