How did Rails generate this path from our model and controller - ruby-on-rails

Ok I kind of understand this part: CRUD verbs and actions http://guides.rubyonrails.org/routing.html#crud-verbs-and-actions
and if I go to the route file of the example I have, I also see a resources :orders in it.
But now in the view of a partial names _carts I am seeing this code:
<%= button_to "Checkout" , new_order_path, method: :get %>
What confuses me is the new_order_path ? Where did that come from? What Rails convention rule is allowing us to right this? Especially where did that "new" come from?

When you use resources :orders in the routes, Rails creates 7 routes for new, create, show, update, destroy, list, and edit. All of them are given names, and new_order_path/new_order_url is related to the new action.
These routes are described at the http://guides.rubyonrails.org/routing.html#paths-and-urls

Those path helpers are automatically generated for resources defined in your routes.rb. You can check what route helpers are available by executing rake routes at the command line. They are shown in the left-most column in the table that prints out.
The general pattern of the paths that are created are like so by default:
new_{singular form of resource}_path - Routes to new on GET
edit_{singular form of resource}_path - Routes to edit on GET
{singular form of resource}_path - Routes to show on GET, destroy on DELETE, update on PUT (Soon to be PATCH in Rails 4)
{plural form of resource}_path - Routes to index on GET and create on POST.
There's also helpers that end in _url instead of _path that provide absolute URLs instead of relative paths. The particular action that is hit in your controller depends on the HTTP verb (GET, PUT, POST, DELETE, etc.) used when visiting those URLs.

Related

Route to /post/new instead of /posts/new in rails?

This is related to a question I asked here: undefined method `posts_path' for #<#<Class:0x007fe3547d97d8>:0x007fe3546d58f0>
I was told to switch my controllers, view etc from "post" to "posts" which fixed the issue, however if I did want to use the URL /post/new, how would I do that without receiving the "undefined method `posts_path'" error I was before?
I don't understand why it's looking for "posts_path" when my controller, model and view are all called "post".
Add this before resources :posts line/block in routes.rb file,
get '/post/new', to: 'posts#new'
When you define routes using resources :posts, by default the route to the new action is /posts/new, So to override the same you need to define custom route like I did above. Also, to search the routes, Rails scans the routes.rb file from top to bottom, whatever matches first is taken. Therefore, to override the default behaviour, I asked you to define this custom route before the default routes.
Hope that helps!
I would suggest that you take a look at Rails Routing Guide.
In short:
Because the model Post describes only one record, it makes sence to call the model Post and not Posts.
With resources :posts within your routes.rb you define that you will have multiple Post objects and you want to expose all CRUD actions with a restfull interface through your controller. Your controller is named PostsController that too makes sence, because your controller provides CRUD actions for all Post objects not only one.
Furthor more rails generate some helpers for every defined route:
posts_(path|url) returns /posts=> shows multiple posts => plural helper name
new_post_(path|url) returns /posts/new => show one post for edit => singular helper name
edit_post_(path|url)(:id) returns /posts/:id/edit => edit one post => singular helper name
photo_(path|url)(:id) => show one post => singular helper name
The route name is always plural because you are always changing the resources. For instance add a new post to the posts resources.
You can also define a singleton resource via resource :geocoder in this case you say you only have one of this thing. For singletons helpers and routes are slightly different. But I saw it until now only rarely.

Incorrectly routing /index to /show in Rails

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.

Including attributes in custom Rails routes

I hope the title is not to misleading, as I don't know a better title for the problem I'm working on:
I have a doctor which belongs to location and specialty. I'd like to route to show action of the doc controller like this:
/dentist/berlin/7
I defined my routes like this:
get ':specialty/:location/:id', to: 'docs#show'
And in my views create the following url to link to the show action of the doc controller:
<%= link_to doc.name, "#{doc.specialty.name}/#{doc.location.name}/#{doc.id}" %>
Is this a good solution to the problem? If not, is there a cleaner way to construct urls like this possibly using resources? What the heck is the name for a this problem?
Thank your very much for your help in advance.
For references, you should have a look at this page (especially the end of section 2.6)
If it is only for a single route, it's okay as you did. But then if you want to have more than one route (like /dentist/berlin/7, /dentist/berlin/7/make_appointment, etc.) you might want to structure a bit more your routes so as to take advantage of rails resources.
For example, instead of
get ':specialty/:location/:id', to: 'doctors#show'
get ':specialty/:location/:id/appointment', to: 'doctors#new_appointment'
post ':specialty/:location/:id/appointment', to: 'doctors#post_appointment'
You could have something like this (the code is almost equivalent, see explanation below)
resources :doctors, path: '/:specialty/:location', only: [:show] do
member do
get 'new_appointment'
post 'create_appointment'
end
end
Explanation
resources will generate the RESTful routes (index, show, edit, new, create, destroy) for the specified controller (doctors_controller I assume)
The 'only' means you don't want to add all the RESTful routes, just the ones specified
Then you want to add member actions, ie. actions that can be executed on a particular item of the collection. You can chose different syntaxes
resources :doctors do
member do
# Everything here will have the prefix /:id so the action applies to a particular item
end
end
# OR
resources :doctors do
get 'new_appointement', on: :member
end
By default, the controller action is the same as the path name you give, but you can also override it
member do
get 'appointment', action: 'new_appointment'
post 'appointment', action: 'post_appointment'
end
Rails has some wonderful helpers when it comes to routing !
The correct approach is to give your route a name, like this:
get ':specialty/:location/:id', to: 'docs#show', as: 'docs_show'
Then you can use it like this:
<%= link_to doc.name, docs_show_path(doc.specialty.name, doc.location.name, doc.id) %>
Note 1:
Rails appends _path at the end of the route names you define.
Note 2:
You can see all the available named routes by executing rake routes.

How do I specify destroy path helper in a view of my Rails app?

I have a model Category in my Rails app. According to rails RESTful Routes, I can perform CRUD Operations on model, having resources: categories defined in my routes.rb.
But how do i define destroy path helper in my view to perform DELETE action, just like edit_category_path(#category) to edit the record. I tried like this
destroy_category_path(#category) but getting error as
undefined method `destroy_category_path' for #<#<Class:0x00000005371298>:0x000000053734f8>
The path is exactly the same as the show action ('/categories/:id'), but you also need to specify the DELETE HTTP method:
button_to #category, method: :delete
Note, it is not considered safe to use links having destructive/constructive actions, as those might be visited by robots.
There is a path helper for delete, but Rails defaults to having this route not defined. To activate the helper you need to add delete to your resourceful routes in your routes.rb file.
resources :categories do
member do
get :delete
end
end
Once you've done that you should be able to use delete_category_path(#category).
Then inside your category you can call destroy on the object from your delete action.

What does xxxx_path mean in ruby on rails

I try to add new controller and model use name foo and foos_controller, hope foos_path can redirect. Doesn't work.
A origin code here (working):
href="<%= contacts_path %>"
After I add new controller and model follow name convention I try use the same (Not working):
href="<%= foos_path %>"
And this contacts_path is not defined anywhere else in rb project.
what does xxxx_path mean and how to use it?
Rails follows convention to handle roots of application
when we execute this command
rails g scaffold foo
it generates routes along with your model, controller and views.
it generates a line in routes.rb as
resources :foo
this line makes you access all the actions of your controller
for example:
foos_path: # redirects you to the index page of your foos controller
new_foo_path: # redirects you to the create page of your foos controller etc.,
please go through this link for reference: http://guides.rubyonrails.org/routing.html
If you go to your terminal and type rake routes, it will list your currently defined routes. On the left side you'll have their prefix. For example, contacts might route to the index action in ContactsController.
The path suffix is a way of referring to those routes inside your code.
If foos_path is giving you an error, that means you either have not yet defined that route for the resource, or you have but it is called something else (if you defined it manually with the as: option).
More info can be found in the Rails Guide for Routing.
You'll be best reading up on this documentation
Path Helpers
Basically, the path_helpers of Rails are designed to help you define routes for your links etc in the most efficient way possible.
The bottom line is the path helper will take routes defined in your config/routes.rb and then allow you to call them dynamically - IE:
#config/routes.rb
resources :photos #-> photos_path
The path names are typically from your controllers, allowing you to route to the various actions inside them. As Rails is built around being a resourceful structure, it will by default create routes for the "standard" controller actions:
link_to
In order to use the path helpers effectively, you'll be best using the rake routes command in cmd, or by simply typing an invalid url into your app's address bar
I notice you're using the standard HTML <a href=""> tag in your question. You'll be much better suited to using the link_to helper of Rails:
<%= link_to "text", your_path %>

Resources