When should I create named routes in Rails? - ruby-on-rails

I'm confused by Rails 3 resource routes. I have following line in my routes.rb
resources :dungeons, only: [ :index, :destroy, :create, :update, :show ]
When I inspect what named routes are create with rake routes, I get:
dungeons GET /dungeons(.:format) dungeons#index
POST /dungeons(.:format) dungeons#create
dungeon GET /dungeons/:id(.:format) dungeons#show
PUT /dungeons/:id(.:format) dungeons#update
DELETE /dungeons/:id(.:format) dungeons#destroy
Why are there only named routes for the routes with a http get method? If I want to create a link to the destroy action, I have to use something like { :action => 'destroy', :method => :delete, :id => dungeon.id } instead of simply destroy_dungeon_path( dungeon ). Is there something wrong with my routes.rb?

Nothing wrong with your routes file. This is the destroy route: dungeon_path(id)
You have to send a DELETE request to trigger it. The show, update and destroy got the same named_route, the only thing what is different is the type of Request (GET for show, PUT for update or DELETE for destroy)
Here everything you need to know routing in Rails3: http://guides.rubyonrails.org/routing.html

Related

Ruby-on-rails - Destroy - Error: No route matches [GET]

I am using destroy
In my view, I have:
#delete_archive_modal.modal.fade
.modal-header
%h3
%i.icon-exclamation-sign
Attention
.modal-body
%p= "Are you sure you want to delete this portal?"
.modal-footer
%a.btn{"data-dismiss" => "modal", :href => "#"} Cancel
= link_to 'Delete', delete_portal_path(portal)
Routes:
resources :portals do
resources :pill_tabs, only: [:show, :edit]
resources :page_urls do
collection do
get :redirects
end
end
resources :zero_touch_configs do
member do
get :history
end
end
member do
get :navigation
get :history
get :sitemap
get :url_list
post :generate_sitemap
post :add_modules
post :archive
post :delete
end
collection do
get :index, path: '/'
get :new, path: '/new(/:portal_type)'
get :accessible_sites
get :archive_index
get :delete
end
And in my controller:
def destroy
#portal = Portal.find(params[:id])
#portal.destroy
flash[:notice] = 'Portal deleted successfully.'
redirect_to action: :archive_index
end
routes:
portals GET /portals(.:format) portals#index
GET /portals/new(/:portal_type)(.:format) portals#new
accessible_sites_portals GET /portals/accessible_sites(.:format) portals#accessible_sites
archive_index_portals GET /portals/archive_index(.:format) portals#archive_index
delete_portals GET /portals/delete(.:format) portals#delete
history_portal_stack_wrapper GET /portals/:portal_id/stack_wrappers/:id/history(.:format) stack_wrappers#history
drafts_portal_stack_wrapper GET /portals/:portal_id/stack_wrappers/:id/drafts(.:format) stack_wrappers#drafts
purge_portal_stack_wrapper GET /portals/:portal_id/stack_wrappers/:id/purge(.:format) stack_wrappers#purge
all_drafts_portal_stack_wrappers GET /portals/:portal_id/stack_wrappers/drafts(.:format) stack_wrappers#all_drafts
portal_stack_wrappers GET /portals/:portal_id/stack_wrappers(.:format) stack_wrappers#index
POST /portals/:portal_id/stack_wrappers(.:format) stack_wrappers#create
new_portal_stack_wrapper GET /portals/:portal_id/stack_wrappers/new(.:format) stack_wrappers#new
edit_portal_stack_wrapper GET /portals/:portal_id/stack_wrappers/:id/edit(.:format) stack_wrappers#edit
portal_stack_wrapper GET /portals/:portal_id/stack_wrappers/:id(.:format) stack_wrappers#show
PATCH /portals/:portal_id/stack_wrappers/:id(.:format) stack_wrappers#update
PUT /portals/:portal_id/stack_wrappers/:id(.:format) stack_wrappers#update
DELETE /portals/:portal_id/stack_wrappers/:id(.:format) stack_wrappers#destroy
history_portal_config_bundle GET /portals/:portal_id/config_bundles/:id/history(.:format) config_bundles#history
portal_config_bundles GET /portals/:portal_id/config_bundles(.:format) config_bundles#index
POST /portals/:portal_id/config_bundles(.:format) config_bundles#create
new_portal_config_bundle GET /portals/:portal_id/config_bundles/new(.:format) config_bundles#new
edit_portal_config_bundle GET /portals/:portal_id/config_bundles/:id/edit(.:format) config_bundles#edit
portal_config_bundle GET /portals/:portal_id/config_bundles/:id(.:format)
But I am getting a routing error and don't know where to go from here...
No route matches [GET] "/portals/asdg/delete"
Can anyone share a guide or point me to documentation that helps me understand what's wrong here?
Try
= link_to 'Delete', portal_path(portal), method: :delete
Here are the all 7 routes for portal
portals GET /portals(.:format) portals#index
POST /portals(.:format) portals#create
new_portal GET /portals/new(.:format) portals#new
edit_portal GET /portals/:id/edit(.:format) portals#edit
portal GET /portals/:id(.:format) portals#show
PATCH /portals/:id(.:format) portals#update
PUT /portals/:id(.:format) portals#update
DELETE /portals/:id(.:format) portals#destroy
And in your routes you have delete_portal path will exist because of
member do
post :delete
end
If you want to call this then you have do define method for this action in your controller and call this path with method: :post
But in RESTful routes delete action have always DELETE method, see in above routes.
There are two issues in your link_to tag.
You used delete_portal_path(portal) but if you run rake routes on your console you will see no such route exist. it have portal_path(portal).
You need to specify method type in route in case of Show(GET default), update(PUT) and delete(DELETE). Because all share same path portal_path(portal).
So your final route should be:
= link_to 'Delete', portal_path(portal), method: :delete
More detail here
You need to define http method when you use delete
= link_to 'Delete', portal_path(portal), method: :delete
It will work.

post to an update action with out an id in rails 4.1.x

I have a controller:
module Xaaron
class PermissionsManagementController < ApplicationController
end
end
chick has create, edit, update, new and destroy.
edit and destroy I was able to do something like:
get 'edit_group_membership' => 'permissions_management#edit', :as => 'edit_group_membership'
get 'remove_group_membership' => 'permissions_management#destroy', :as => 'remove_group_membership'
which allows me to by pass passing in a id. There is no model object for this controller so there is no need for an id. but my question is, how do i post to the update action in rspec and in the form_tag with out passing in an id? and with out it exploding stating that I am missing an id.
in the spec can I do: post :update, id: '', {}? What would I do for form_tag?
You could start with something like this:
# routes.rb
post 'permissions_management' => 'permissions_management#update', as: 'change_permissions_management'
# view
form_tag(change_permissions_management_path)
If it were my app, I would treat this as a singular resource, for which Rails provides out-of-the-box support. As you can see in the rake routes output, the :id param is not required for the show, update and destroy routes.
# routes.rb
resource :permissions_management # note the singular "resource"
# view
form_tag(permissions_management_path)
# $ rake routes | grep permissions_management
permissions_management POST /permissions_management(.:format) permissions_managements#create
new_permissions_management GET /permissions_management/new(.:format) permissions_managements#new
edit_permissions_management GET /permissions_management/edit(.:format) permissions_managements#edit
GET /permissions_management(.:format) permissions_managements#show
PATCH /permissions_management(.:format) permissions_managements#update
PUT /permissions_management(.:format) permissions_managements#update
DELETE /permissions_management(.:format) permissions_managements#destroy

Named routes inserting a . instead of a /

I've been having trouble with named routes in rails 4 (Named route for non resource nesting).
I've moved onto something else, but still struggling with the same problem of named routes for non resource urls.
This is my route from rake routes:
GET /messages/:id/report/:reply_token(.:format) messages#report
messages POST /messages(.:format) messages#create
and my routes.rb
resources :messages, only: [:create] do
member do
get 'report/:reply_token', :action => 'report'#, :as => :message
end
end
Because of the problem I had in my post linked at the top, I'm trying to get a url to the /messages/:id/report/:reply_token route by doing the following:
"#{messages_url(#message, :host => "localhost:3000")}/report/#{#message.reply_token}"
But it's giving me this:
http://localhost:3000/messages.110/report/6bBw22TdaRYcQ3iVzW1ZwA
Why is there a . between the 'messages' and the '110' (message_id)?
Instead of #message, I've also tried #message.id in the messages_url(). I've also tried this: report_message_path(message_id: #message.id, reply_token: #message.reply_token) but got the same error as in my question linked above. I've also tried message_url() instead but it gives undefined method 'message_url'.
You are mixing up routes. messages_url is to generate a URL for create action which does not have ID in its route. Rails assumes 110 is the format and uses the second route (which is named as messages)
messages POST /messages(.:format)
As a solution, name your route like this and also add show action
resources :messages, only: [:create,:show] do
member do
get 'report/:reply_token', :action => 'report' , :as => :custom_message
end
end
And,
custom_message_url(#message, :host => "localhost:3000")
More about naming routes here.
Answerd here already - Rails _path helper generating path with format not id

Rails controller edit action - how to avoid the id to be displayed?

I have a resource named offer. When I edit the offer the URL looks like “/offers/1/edit”. How is it possible to avoid the ID to be displayed in the URL completely?
I want to store the offer ID in the session instead as the offer actions should be public. I’m afraid if one would try to enter different IDs in the URL manually. Is that possible?
My desired URL would look like this: “/offers/edit”.
The create action responds this: render "edit". Here the ID is not displayed, the URL is just “/offers”, fine.
But this response (render "edit") leads to displaying the URL with the ID again, grrr.
Is there a solution to that?
Thanks for your help!
Marc
You can overwrite method to_param in your model
def to_param
your_item.name.parameterize
end
then router will produce something like this “/offers/name_of_your_item/edit”.
You could (although it is a kind of misuse) use a resource mapping instead of a resources.
You could add resource :offers to your routes.rb.
That will give you routes like this:
offers POST /offers(.:format) {:action=>"create", :controller=>"offers"}
new_offers GET /offers/new(.:format) {:action=>"new", :controller=>"offers"}
edit_offers GET /offers/edit(.:format) {:action=>"edit", :controller=>"offers"}
GET /offers(.:format) {:action=>"show", :controller=>"offers"}
PUT /offers(.:format) {:action=>"update", :controller=>"offers"}
DELETE /offers(.:format) {:action=>"destroy", :controller=>"offers"}
Alternatively I would simply not use the standard edit mapping and add my own:
resources :offers, :except => [:edit, :update] do
get :edit, :on => :collection
put :update, :on => :collection
end
If my memory serves me right then the following should work in Rails 2.3.x:
map.resources :offers, :except => [:edit, :update], :collection => { :edit => :get, :update => :put }
I don't have such environment handy so I cannot test it at the moment...

Routing HTTP verbs in Rails

I'm trying to route only an http verb. Say I have a comments resource like so:
map.resources :comments
And would like to be able to destroy all comments by sending a DELETE /comments request. I.e. I want to be able to map just the http verb without the "action name" part of the route. Is this possible?
Cheers
You could do this:
map.resources :comments, :only => :destroy
which produces a route like the following (you can verify with rake routes)
DELETE /comments/:id(.:format) {:controller=>"comments", :action=>"destroy"}
But note that the RESTful destroy is designed for removing a specific record not all records so this route is still expecting an :id parameter. A hack might be to pass some sentinel value for :id representing "all" in your application context.
On the other hand, if your comments belong to another model, then removing the other model would/should remove the comments too. This is conventionally how multiple row deletes might normally occur.
Since this is not standard RESTful action, you will need to use a custom route.
map.connect '/comments',
:controller => 'comments',
:action => "destroy_all",
:conditions => { :method => :delete }
In your controller:
class CommentsController < ApplicationController
# your RESTful actions here
def destroy_all
# destroy all your comments here
end
end
In view, invoke like this:
<%= link_to "delete all comments",
comments_path,
:method => :delete,
:confirm => "Are you sure" %>
ps. I didn't test this code, but I think it should work.

Resources