According to http://guides.rubyonrails.org/routing.html:
HTTP Verb Path Action Used for
GET /photos index display a list of all photos
GET /photos/new new return an HTML form for creating a new photo
POST /photos create create a new photo
GET /photos/:id show display a specific photo
GET /photos/:id/edit edit return an HTML form for editing a photo
PATCH/PUT /photos/:id update update a specific photo
DELETE /photos/:id destroy delete a specific photo
How does rails know when a PATCH/PUT REST is received. I understand the get/post but PATCH/PUT I cannot figure it out. Is something being done internally, like in the input.
Rails figures out which method to call based on whether the form submitted is a form for a new record that has not yet been saved or for a record that already exists in the database.
Read about "resource routing" in the document you referenced at the top of your post.
Also, run rake routes to see how rails is currently configured to route.
In The Terminal Type:
$rake routes
and hit enter
Prefix Verb URI Pattern Controller#Action
root GET / welcome#index
Related
I have a simple question about rails.
I followed a tutorial (from CrashLearner).
In that tutorial we have a simple resource message that generates the regular following routes (excerpt from rake routes)
Prefix Verb URI Pattern Controller#Action
messages GET /messages(.:format) messages#index
POST /messages(.:format) messages#create
new_message GET /messages/new(.:format) messages#new
edit_message GET /messages/:id/edit(.:format) messages#edit
message GET /messages/:id(.:format) messages#show
PATCH /messages/:id(.:format) messages#update
PUT /messages/:id(.:format) messages#update
DELETE /messages/:id(.:format) messages#destroy
As I understand the route to get to the show action of this controller is like something /messages/17, I mean we have to put the :id of that particular message we want to view.
So, if I needed to redirect the user to this message view after he modified it (in the #update action) I should use:
redirect_to message_path(17)
But it turns out that omitting this :id actually works great:
redirect_to message_path
Why and how this last one work ?
Since this works from an action that actually received the :id param I suppose that the controller keep it in memory and pass it through by default under the hood when it is missing but I would like to understand where this behavior come from ?
I found nothing in the rails documentation.
Here is the github repository of the tutorial, so the exact specific place of the above line is here in this controller.
And I confirm that this works.
There is also a Comment resource that is nested from the previous Message resource.
As you can see in that controller on the update action, after updating a comment (which is nested within a message) the controller redirects to the message_path but in that case the :id parameter is present through the instance variable #message (and I learned that this works because the object Message respond to an .id method otherwise it should be #message.id)
I supposed that the reason that why here the :id is still passed is because we are in the Comments controller and the :id of another resource could not be passed under the hood, thus why it is explicitely written.
I don't have another explication..
Can anyone explain me why this works ?
I found this in Rails source:
Missing routes keys may be filled in from the current request's
parameters (e.g. +:controller+, +:action+, +:id+ and any other
parameters that are placed in the path).
So here :id exists in the current request params and it's used for this route.
If you define singular resource you will have show action without :id param
http://edgeguides.rubyonrails.org/routing.html#singular-resources
I am trying to create a separate :show route, to use route globbing on the :id parameter. For this, I created a resource route without the show route and also a separate show route:
resource :test, except: [:show]
get 'test/*id', to: 'test#show', as: :test
the problem is that I receive the error: You may have defined two routes with the same name using the:asoption, or you may be overriding a route already defined by a resource with the same naming.
If I remove as: :test it works. rails routes shows:
tests POST /tests(.:format)
new_test GET /tests/new(.:format)
edit_test GET /tests/:id/edit(.:format)
test PATCH /tests/:id(.:format) <-- WHY??
DELETE /tests/:id(.:format)
GET /tests/*id(.:format)
as you can see, resources renamed the PATCH route to :test. If I remove that route, the DELETE route is named test, and so on. How can I stop resources from using the test route name specifically? I cannot move my globbing route above the resource block obviously because then all other routes are globbed too.
What I want:
tests POST /tests(.:format)
new_test GET /tests/new(.:format)
edit_test GET /tests/:id/edit(.:format)
PATCH /tests/:id(.:format)
DELETE /tests/:id(.:format)
test GET /tests/*id(.:format)
Rails uses the same prefix (say, in your case "test") for all those four routes[show(GET), update(PUT/PATCH), destroy(DELETE)] and it recognises the different routes with the HTTP Verbs.
I don't understand your problem, but if you look on Rails Guides "Singular Resources" you can see:
Path Controller #Action Used for
GET /geocoder/new geocoders#new return an HTML form for creating the geocoder
POST /geocoder geocoders#create create the new geocoder
GET /geocoder geocoders#show display the one and only geocoder resource
GET /geocoder/edit geocoders#edit return an HTML form for editing the geocoder
PATCH/PUT /geocoder geocoders#update update the one and only geocoder resource
DELETE /geocoder geocoders#destroy delete the geocoder resource
show, create, update and destroy use the same route but with different HTTP verbs. And in your case, test wrote with PATCH verb, because this verb earlier in the table, empty name means that it uses the same name as upper line.
First of all,
test PATCH /tests/:id(.:format) <-- WHY??
DELETE /tests/:id(.:format)
GET /tests/*id(.:format)
Patch is for your Update method routes.
Delete is for destroy method route.
that add by your custom route generated by get 'test/*id', to: 'test#show', as: :test
So, here you can make your show route with different alias. Ex like using as :show_test
There must be an obvious answer to this, but I'm at a loss.
I have a Rails app which tracks sites. For whatever reason, localhost:3000/sites leads to my index page. However, localhost:3000/sites/index leads to my show page.
Why is this?
Below is the routes file:
Rails.application.routes.draw do
resources :sites
Below is the sites controller:
class SitesController < ApplicationController
def index
end
def show
end
end
In views/sites, there is the index.html.erb and show.html.erb files. The former displays at /sites, the latter displays at /sites/index (and /sites/show as one would expect).
Thanks for any help!
UPDATE:
When I rake routes, I get:
Prefix Verb URI Pattern Controller#Action
sites GET /sites(.:format) sites#index
POST /sites(.:format) sites#create
new_site GET /sites/new(.:format) sites#new
edit_site GET /sites/:id/edit(.:format) sites#edit
site GET /sites/:id(.:format) sites#show
PATCH /sites/:id(.:format) sites#update
PUT /sites/:id(.:format) sites#update
DELETE /sites/:id(.:format) sites#destroy
These routes are what one would expect, but I guess I'm just surprised that sites/index presumes index is an :id and therefore routes the request to show.
I suppose I had never explicitly encountered that behavior before.
There are 7 basic actions in a controller by default, only 2 of them are matched by name in the url - (new and edit). These 2 are HTML constructs, they are just a way of rendering a form.
The other 5 (index, show, update, create, destroy) are the more basic routes and do the work to display and modify resources. They are referenced by only two url patterns (the two patterns you mentioned above - eg '/sites' and '/sites/:id'). They are differentiated by the method that goes along with the request: (Patch, Post, Get, Delete). So, "/sites" would be used for create and index. "/sites/:id" would be used for show, destroy, and update.
The action in the controller is not referenced by the url exactly - the url pattern and the request method together are used to call the associated controller method.
In the request "/sites/index", as the string "index" is in the url, the only route that matches is one that has a variable after "/sites/". :id is just a variable, not necessarily an integer. Since the request was a GET, the first (and only) route match is sites#show. "index" will be the value of params[:id] passed into the show action.
This is the way routing works in Rails. Take a look at Rails routing to get a better understanding of how this works. Especially the
Rails resource routing section.
Generally when you setup a resource route as you did the urls would be as follows:
example.com/sites #=> index page
example.com/sites/:id #=> show page. A specific site, where :id would be the unique identifier
# Here's an example URL with a specific site
example.com/sites/stackoverflow
Your index page is at: localhost:3000/sites
Navigate to localhost:3000/rails/info/routes to see your full app routes in development mode.
I'm a beginner with Rails, and I ready all this very usefull tutoriel (French) But I have some other question..
I learn how the basic Rails router works (based from Controller name) :
RequĂȘte HTTP URL Action
-----------------------------------
GET /users index
GET /users/1 show
GET /users/new new
POST /users create
GET /users/1/edit edit
PUT /users/1 update
DELETE /users/1 destroy
But I want make some modifications :
1/ SOE
I need to update route for user retrieve (show, update, ..) and i want use #user[:username] on URI instead of #user[:id]
So in my case : /users/arthur instead of /users/1
2/ Multilingual
On the same type of problem, i want add one the start of the URI the ISO code for each country (ex : /fr/users/) and create alias on my URI.
For example, before the Rails router was initialized I want update all routes like :
/utilisateurs/... -> /users/...
/produits/... -> /products/...
Can I do it easly ?! And these changes may be applicable by the link_to function ?
So if i'm call like_to #user ( with #user data : {'name'=>'arthur', 'lang'=>'fr'} ) the function should return /fr/utilisateurs/arthur instead of /users/1
Thank you all for helping !
You can use Translated Paths for the multilingual definitions found here. As for the use of username for the param you can follow this, basically you override to_param and that will be used to generate the url when using link_to and other helpers.
I want to invoke the "create" method of my Rails controller to insert a new record.
Calling http://localhost:3000/books.json using HTTP POST invokes the books#create method, and allows me to insert a new book.
This works fine, but the JSON response returns ALL books that exist in the database. It seems like calling books#create somehow also invokes books#index.
How can I restrict the JSON output of books#create to only the last inserted record instead of all records?
You're probably calling the route using a GET request.
Try curl -d '' http://localhost:3000/books.json to make a POST request
If that doesn't work, then paste the output of rake routes and the BooksController#create action.
In route you should specify for json request
resources :books , :format => 'json'
After creating record successfully you can redirect it to show page of that record with id or
you can tweak your index method conditionally means if you pass id to index it will show only that record else show all the available records.