In order to more clearly understand exactly what "resources" is doing in the Ruby on Rails routes.rb file, I want to write under it the exact code it is replacing.
When I run rake routes I get this:
users GET /users(.:format) users#index
POST /users(.:format) users#create
new_user GET /users/new(.:format) users#new
edit_user GET /users/:id/edit(.:format) users#edit
user GET /users/:id(.:format) users#show
PATCH /users/:id(.:format) users#update
PUT /users/:id(.:format) users#update
DELETE /users/:id(.:format) users#destroy
Can someone help me fill in the blanks below so I can understand this more clearly:
resources 'users'
# get 'users' => 'users#index"
# post ...
# get ...
# get ...
# patch ...
# put ...
# delete ...
The equivalent code could be expressed as:
get 'users', to: 'users#index'
post 'users', to: 'users#create'
get 'users/new', to: 'users#new', as: 'new_user'
get 'users/:id/edit', to: 'users#edit', as: 'edit_user'
get 'users/:id', to: 'users#show', as: 'user'
patch 'users/:id', to: 'users#update'
put 'users/:id', to: 'users#update'
delete 'users/:id', to: 'users#destroy'
Brad werths answer is what you need.
To give you some more context, you also need to appreciate how the resourceful routing system works in Rails...
Resource routing allows you to quickly declare all of the common routes for a given resourceful controller. Instead of declaring separate routes for your index, show, new, edit, create, update and destroy actions, a resourceful route declares them in a single line of code.
Basically, each time you call resources, you're telling rails to build a set of routes for a controller designed around the "resourceful" principle.
"Resourceful" actions through the Internet are defined by wikipedia as follows:
HTTP functions as a request-response protocol in the client-server computing model. A web browser, for example, may be the client and an application running on a computer hosting a web site may be the server. The client submits an HTTP request message to the server. The server, which provides resources such as HTML files and other content, or performs other functions on behalf of the client, returns a response message to the client. The response contains completion status information about the request and may also contain requested content in its message body.
All of this make sense when you understand that Ruby/Rails is object orientated. This means everything you do in your application has to resolve around the initialization & maintenance of "objects".
Objects are basically your models - they are created, edited and destroyed (CRUD -- create read update destroy) with your controller actions. Therefore, to give you a set of standardized routes, you'll be able to use the following:
If you want to see your routes like how brad has outlined, you'll want to run rake routes
--
Good resource here: https://softwareengineering.stackexchange.com/questions/120716/difference-between-rest-and-crud
Related
Rails 5.2.2
In my routes.rb file, I have:
resources :users, only: [:index, :new, :create, :update] do
put 'disable', on: :member
end
When I do rake routes, I get:
disable_user PUT /users/:id/disable(.:format) users#disable
users GET /users(.:format) users#index
POST /users(.:format) users#create
new_user GET /users/new(.:format) users#new
user PATCH /users/:id(.:format) users#update
PUT /users/:id(.:format) users#update
Why do I have a duplicate of the update route? or this just a visual artifact of the rake route command?
Rails originally only used the PUT http verb for updates. In 2012 PATCH was declared the new primary HTTP method for updates because of the semantics of how IETF defines PUT.
Now let’s say a web application has an Invoice model with a paid flag
that indicates whether the invoice has been paid. How do you set that
flag in a RESTful way? Submitting paid=1 via PUT to /invoices/:id does
not conform to HTTP semantics, because such request would not be
sending a complete representation of the invoice for replacement.
The entire discussion on the hows and why's can be found in issue #348.
However for legacy compatibility reasons the resources and resource macros still generate a PUT route. This was a better compromise than breaking the Rails router to treat PUT and PATCH identically.
Why this legacy compatibility still is here in 2019 is another really good question.
I have the following routes.rb
resource :user, :only => [ :edit, :update ] do
collection do
get :tax_info
get :payment_info
put :payment_info
and would like to reference the get payment_info via an rspec matcher like this:
expect(response).to redirect_to(user_payment_info)
What would be the proper way to reference that path? I have tried user_payment_info and edit_user_payment_info?
Edit #1
Show output of rake routes on this controller
You're missing the _path portion that rails generates for all routes. Your rspec matcher should look like this:
expect(response).to redirect_to(user_payment_info_path)
The information returned when running rake routes will look similar to this:
GET /users/:id(.:format) user#show
tax_info_user GET /user/tax_info(.:format) users#tax_info
payment_info_user GET /user/payment_info(.:format) users#payment_info
PUT /user/payment_info(.:format) users#payment_info
edit_user GET /user/edit(.:format) users#edit
user PATCH /user(.:format) users#update
PUT /user(.:format) users#update
You can see on the left hand side there is a column that denotes the prefix for the url and path helpers that rails is going to generate. You can see this defined in the Rails 3.2 routing documentation.
Im trying to learn to dry up my code a bit but have come across a issue,
Im scoping my routes with controller and path options
scope path: '/administrators', controller: :administrators do
get 'unverified' => :unverified
patch 'verify/:id' => :verify
get 'reported' => :reported
get 'ban_user' => :ban_user
patch 'execute_ban/:id' => :execute_ban
end
So this is what ive done so far, all the get links are working correctly...
but this is making the patch 'execute_ban/:id' => :execute_ban become a extension of ban user like this: (also the same with verify)
verified GET /administrators/unverified(.:format) administrators#unverifie
PATCH /administrators/verify/:id(.:format) administrators#verify
reported GET /administrators/reported(.:format) administrators#reported
ban_user GET /administrators/ban_user(.:format) administrators#ban_user
PATCH /administrators/execute_ban/:id(.:format) administrators#execute_ban
now ive changed my link_to route = link_to 'ban', ban_user_path(x.id), method: :patch
but its throwing an routing error saying no path matches.
Is there something im missing, any insight would aooreciated as always.
Thanks
Why not go for a more restful design that centers around the resource being modified?
Rails.application.routes.draw do
resources :users do
get :unverified, on: :collection
get :reported, on: :collection
get :ban
patch :ban, action: 'execute_ban'
end
end
You don't need different paths for the form and acting on a resource - use the HTTP verb instead.
Prefix Verb URI Pattern Controller#Action
unverified_users GET /users/unverified(.:format) users#unverified
reported_users GET /users/reported(.:format) users#reported
user_ban GET /users/:user_id/ban(.:format) users#ban
PATCH /users/:user_id/ban(.:format) users#execute_ban
users GET /users(.:format) users#index
POST /users(.:format) users#create
new_user GET /users/new(.:format) users#new
edit_user GET /users/:id/edit(.:format) users#edit
user GET /users/:id(.:format) users#show
PATCH /users/:id(.:format) users#update
PUT /users/:id(.:format) users#update
DELETE /users/:id(.:format) users#destroy
If you are adding a separate controller just for authorization purposes it's an anti-pattern of sorts since you are just adding more complexity for something that should be handled by Pundit/CanCanCan.
I’m using Rails 4.2.5. I’m trying to set up my controller so that when a logged in user visits /users/edit, they see my form where they can edit some of their profiles. So in config/routes.rb I have
resources :users
…
get "users/edit" => "users#edit"
then in “app/controllers/users_controller.rb” I have
def edit
#user = User.find(session["user_id"])
render 'edit'
end
but when I visit “http://localhost:3000/users/edit” in a browser, I get the error
The action 'show' could not be found for UsersController
It is true I have no “show” method in my controller, but that is not where I want the user to go. I want them going to the edit method.
You are trying to go to the show action with this link:
http://localhost:3000/users/edit
You have this route for the show action:
GET /users/:id(.:format) users#show
(:id) is (edit)
Because you have defined first RESTful route:
resources :users
Which includes all routes listed below:
users_path GET /users(.:format) users#index
POST /users(.:format) users#create
new_user_path GET /users/new(.:format) users#new
edit_user_path GET /users/:id/edit(.:format) users#edit
user_path GET /users/:id(.:format) users#show
PATCH /users/:id(.:format) users#update
PUT /users/:id(.:format) users#update
DELETE /users/:id(.:format) users#destroy
and then
get "users/edit" => "users#edit"
Rails always finds first match. In this case show action of RESTFul routes will be applied:
GET /users/:id(.:format) users#show
and the other route will be ignored.
Solution: Change the order of the routes. That way edit route will be applied first.
The problem is that you're mixing a resource route with your own edit method, and "Rails routes are matched in the order they are specified" so it's matching the resources show route users/:id and stopping there.
You need to move your edit route above the resource.
Alternatively, read the linked guide and see if you can add edit as a collection route to the resource, and except the resources edit method. You may also need to except the show method, but it's worth having a play and seeing what you come up with. Routing is an important aspect and worth time to understand.
remove get "users/edit" => "users#edit" from your routes, change to resources :users, only: [:edit] (or more if actions you need them), remove the render 'edit' from your controller (default action).
Visit http://localhost:3000/users/1/edit to see the edit page for user_id 1 (there can't be an edit page for all users, you have to specify the id)
I am trying to make a POST request to /api/kpi?data=some+stuff:
curl -i http://127.0.0.1:9010/api/create_kpi -F data="some stuff"
but I'm getting a 404.
My routes are:
# config/routes.rb
namespace :api do
resource :kpi, :except => [:edit, :destroy]
end
Which should hit my controller
# app/controllers/api/kpi_controller.rb
class Api::KpiController < ApplicationController
def create
temp = Kpi.new(params[:data])
end
end
So I am guessing the paths are not correct. Right? I am having a hard time understanding whether my route is incorrect, or the controller, or the call.
When you get a 404, check your routes. It usually means there is no route to the controller to reach. Routes are what makes the link between URLs and controllers. If your controller was getting hit, it'd either work or give you a runtime error.
Inspect your routes by running rake routes. It's a very helpful tool. It should give you something like this:
users GET /users(.:format) users#index
POST /users(.:format) users#create
new_user GET /users/new(.:format) users#new
edit_user GET /users/:id/edit(.:format) users#edit
You can see that it gives you the mapping of what [method, URL] request will hit which [controller, action]. For example, here, POST /users will trigger action create of UsersController.
Given a controller/resource name, Rails will, by convention, go looking for the plural of that name. For example, given resources :user, Rails will go looking for UsersController in file app/controllers/users_controller.rb. (Path/file names have to match the name!)
#yfedblum talks about the use of singular and plural in Rails into more detail.