Rails Routing: POST action to destroy content - ruby-on-rails

I want to have an endpoint to destroy an instance of a model through a POST action like the Twitter API does:
statuses/destroy/:id
How would I define this route in the route file? I'm at a loss.

it may look better if you have other actions in the same resource in rails 3
resources :statuses, :only => [:index, :create]
collection do
post 'destroy/:id', :action => :destroy
end
end

I'm not sure if this is what you're trying to do but add this to your config/routes.rb should do the trick:
match 'statuses/destroy/:id' => 'statuses#destroy', :via => :post
(I've found it in the Rails Routing Guide)

Related

Ruby on Rails Route

how can I generate a RoR route like this one:
Prefix: gateway
verb: post
URI Pattern: /region/:id/gateway
Controller#Action: region#gateway
I tried with
resources :region, :only => :show do
post :gateway, :only => :show
end
but is generating by default a route to show the regions
/region/:id(.:format)
I want to skip the regions show action and only keep it the /region/:id/gateway route
post "gateway/region/:id/gateway" => "region#gateway"
Have a look to Rails routing documentation. It's well documented.
If You want to use resources, You may write:
resources :region do
member do
post :gateway
end
end
It will be recognized as:
region/:id/gateway
You can't use "only" because it reduce to one action!

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

Why resources on collection has different routing helper then regular post

In my routes.rb I had this resource
resources :home_screen_buttons do
post :update_multiple, :on => :collection
end
update_multiple helper is update_multiple_home_screen_buttons
Then I decided to remove resource because i need only update_multiple method in my controller, so I changed routes.rb to
post "home_screen_buttons/update_multiple"
It create helper home_screen_buttons_update_multiple instead of update_multiple_home_screen_buttons
Why it has different routing helper name?
It makes sense that :on => :collection has different helper then :on => :member, but is there any other way then adding :as => :update_multiple_home_screen_buttons to my post method for same behavior?
This is how Rails does this. When match is used, it maps the URI to the action and creates the corresponding helper path as controller_action_path
but when it is used as collection, that becomes RESTful action for that resource and Rails gives it a logical name relating to a collection. As quoted as an example here:
resources :photos do
collection do
get 'search'
end
end
generates search_photos_path.
You could have done this:
resources :home_screen_buttons, :only => [:update_multiple] do
post :update_multiple, :on => :collection
end

How to declare a rails resource with a parameter for new action?

I have a model named Entree for which the new action needs a parameter, the id of another model named Cave. I don't want to nest Entree in Cave since Cave is already nested.
What I did was declaring the resource Entree as follow in routes.rb:
resources :entrees, :except => [:new]
match "/entrees/new/:id", :to => "Entrees#new", :as => 'new_entree'
That works, but the problem is when there's an error in the create action, I want to display the page again with the invalid input. But since there's no new action, I must do a redirect_to new_entree_path, which does not keep the user input.
I have tried the following (simplest) route:
resources :entrees
But then the path http://localhost:3000/entrees/new/32 returns an error:
No route matches [GET] "/entrees/new/32"
The question is, how can I declare the Entree resource in the routes file with a parameter for the new action ?
I'm not sure if that's a hack or not, but the following works and seems cleaner than 2-levels nesting.
resources :entrees, :except => [:new] do
collection do
get 'new/:id', :to => "entrees#new", :as => 'new'
end
end
Now I can do a render "new" instead of a redirect_to.
I must say that I must have asked my question wrongly, my bad.
Rails has a route helper called path_names that does this:
resources :entrees, path_names: { new: 'new/:id' }
To improve gwik 's solution (which in fact didn't work for me):
resources :things, except: [:new] do
new do
get ':param', to: 'things#new', as: ''
end
end
It gets you new_thing_* helpers (instead of new_things_*) for free.
If you want to use Rails resource routes, you will have to nested them according to how they work
resources :caves do
resources :entrees
end
to get the route /caves/70/entrees/new
Otherwise, you are in a world of creating manual match routes.
match "/entrees/new/:id", :to => "entrees#new", :as => 'new_entrees'
I do not understand why you are forced to use a redirect? The new_entrees route is valid. You will not be able to use the form_for helper, since it is not a resource, but the form_tag helper will work.
UPDATE: Render and Route
The Route does not directly change what view is rendered in the Controller. That is determined by the controller itself. Render examples:
render :new will render the new action's view
render 'entrees/new' will render the entrees/new template
I found this generates the correct new_thing_path method not new_things_path as Antoine's solution.
resources :things, :except => [:new] do
with_scope_level(:new) do
get 'new/:param', :to => "things#new", :as => ''
end
end

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