In Michael Hartel's Rails Tutorial he suggests creating the following route in oder to logout users:
delete 'logout' => 'sessions#destroy'
This seems to add some unnecessary legwork throughout the application, e.g., requiring links to include method: "delete". The following also works perfectly:
get 'logout' => 'sessions#destroy'
Why is the convention to use the "delete" method and not simply "get"? Is there some hidden advantage?
There are a number of reasons, two of the most vital:
Prevents inclusion of stray "destroy" links (using DELETE in a destroy link means you have to explicitly define it)
Forms part of the "resourceful" structure of HTTP (not as important, but if you want to create "real" web apps, it is vital for using the correct URL structure)
Links
The most important reason - for many - is the inclusion of stray "destroy" links in your views.
To destroy an object (which is what the DELETE method is meant to denote) is a serious endeavour -- you need to make sure the links you include are legitimate & cannot be confused.
Explicitly declaring method: :delete adds an immediate level of authorization to the links, enough to give you assurance the link is there for a reason.
The number of times I have seen people neglecting the method switch of their links is ridiculous -- imagine if you had the ability to destroy some data with such haphazard structure. You'd have so many mistakes in your code...
-
Resources
The second reason is more important - it retains the resourceful nature of HTTP:
HTTP resources are identified and located on the network by uniform resource locators (URLs), using the uniform resource identifier (URI) schemes http and https. URIs and hyperlinks in Hypertext Markup Language (HTML) documents form inter-linked hypertext documents.
Simply, the real structure of HTTP (the protocol which powers the "web") is such that you're meant to load resources through it.
This video explains it quite well:
These resources are meant to be located through specific urls, and if you think about it properly, only have a certain number of permutations which would allow the resource to be managed.
Indeed, when it comes to Rails, many engage with the resourceful nature of the web for the first time, hence questions like this. I didn't know about it until working with Rails... which is why it's so important to understand why this type of setup works so well:
The above shows what happens when using the rails resources helper (which I'd strongly recommend you use):
#config/routes.rb
resources :sessions, path: "", path_names: { destroy: "logout" }
This will create a set of "resourceful" links (as above). These links basically denote how you should handle the resources on your app, of course placing the DELETE method with the destroy action.
You don't have to use DELETE but it certainly makes your application more versatile!
Get is different in DELETE Request.
GET - Requests data from a specified resource
DELETE Deletes the specified resource
See HTTP REQUEST
delete 'logout' => 'sessions#destroy'
The main target is to make meaningful/semantic http requests.
since it corresponds to deleting session object via destroy action; RESTful recommends to use semantic HTTP verb delete rather than get. Moreover, Rails maps delete verb to destroy action by default.
Since you are not getting anything after you delete session rather you are redirected to somewhere else; so it is recommended to make AJAX calls with delete method.
For more info see this
https://parse.com/docs/rest/guide
Related
So, I work with a bit of a behemoth. A 15-year-old rails app which has a few... hundred... controllers, all with their own routes.
Perhaps unsurprisingly, the page loads aren't the snappiest (although not so slow it poses a problem), and this got me thinking.
Is the order in which the routes are defined significant?
Will routes defined later on in the list take longer to match, or are they indexed to speed up the searching process?
RailsGuides mentions this
Rails routes are matched in the order they are specified, so if you
have a resources :photos above a get 'photos/poll' the show action’s
route for the resources line will be matched before the get line. To
fix this, move the get line above the resources line so that it is
matched first.
Having a lot of RESTful routes actually can affect the speed of the process , Documentation actually hints at this
If your application has many RESTful routes, using :only and :except to generate only the routes that you actually need can cut down on memory use and speed up the routing process.
Current Router in rails creates a graph to optimize routes lookup.
Order matters because two routes that matches the same url will trigger the first one defined, but the router does not try each route on a sequential order.
This RailsConf talk explains how the Router works https://www.youtube.com/watch?v=lEC-QoZeBkM
If you find your page not responding fast enough I really doubt the router is the problem, you should profile the request (use something like mini-profiler).
Say that I have a Customers and an Orders tables, where each Customer may have many Orders.
Since in rails we are encouraged to represent these resources in a RESTful style, each of our resources, will respond to the following actions
index
show
edit
new
create
delete
So far, it all is very fair and plain. But now say that each time i open the show page of my Customer, i want to show a detail table containing all his/her orders.
This is a very common need, but doesn't this "unclean" the correctness of restful approach?
Is there some workaround, like "mashing" the two resources at a "view level", leaving them separate from the rest point of view?
Rails' default conventions ensure a RESTful application, and the only way this might become non-restful would be if you used custom-names on the routes, in which case you would have you add an extra bit of code to specify the HTTP method.
So, to accomplish what you're suggesting, at the view level, you may have something like this:
app/views/customers/show.html.erb
....
<% if customer.orders.any? %> #the orders method is provided on `customer` by defining the `has_many` and `belong_to` associations
<%= render #orders $>
And you would make sure to define #orders in the show action of the customers_controller.rb file.
This not only is RESTful, but also works within Rails' default conventions.
Those actions you list are not what makes something RESTful. There are a bunch of characteristics an application must have to be considered RESTful. Some of these characteristics are:
it is thought of as a repository of resources
resources are identified by a URI
there is a uniform interface for interacting with resources - the HTTP verbs of GET, POST, PUT, DELETE, etc.
Rails takes care of receiving HTTP requests and calling your application's functionality, regardless of whether it is RESTful in nature or not, through routing. Rails routing takes those HTTP verbs I mentioned, in combination with a URI, and determines which controller to call. By default Rails follows the RESTful paradigm, and by convention will map verb/URI combinations to those actions you listed - but the actions themselves, and the fact that they are lumped into a single controller, are not part of REST - they are just the rails convention.
In fact, the rails default routing maps 4 different resources to that single controller and its actions:
/customers // the list of all customers, GET/POST -> index/create
/customers/new // a form for creating a customer, GET -> new
/customers/{id} // a single customer, GET/PUT/DELETE -> show/update/destroy
/customers/{id}/edit // a form for editing a customer, GET -> edit
Resources can contain sub-resources, and Rails completely supports that. A sub-resource might be:
/customers/{id}/orders // the list of all orders for a particular customer
Another key part of REST is that it supports a resource having different representations, whether that is HTML, XML, JSON, etc. Clients use HTTP headers to convey what representation they are passing into the app (using the Content-Type header) and (usually) what they will accept in response (using the Accept header).
Its up to the application to determine what a resource representation looks like. Typically a resource will either be "thin" or "fat". A "thin" resource is one that simply has links to its sub-resources and further calls must be made to get them. A "fat" resource will contain the fully-fleshed out sub-resources it contains. Typically with an HTML representation, an application will return some form of "fat" resource. There is nothing non-RESTful about this - and is exactly what you are describing you want for your application.
So that was my long way of saying "don't be afraid of not being RESTful by displaying sub-resources - it's perfectly OK" :-)
Ok so this is a basic routing question for a rails 3 application. I have a controller called contact_infos. For the edit action I want to match the route like the following /contact_infos/id/action. The reason I'm doing this is specifically for ajax functionality. Here's what I've done so far. This route worked fine.
match ':controller(/:id(/:action))(.:format)'
But this route breaks my catch-all route of.
match ':controller(/:action(/:id))(.:format)'
so it is not acceptable for my application.
I know I could target my specific route in the following way
controller :contact_infos do
end
But I'm unsure how to match the url as /contact_infos/id/action only for the edit action without breaking any other contact_infos actions.
Any ideas?
If you give the right answer I will definitely rate you up.
Thanks!
Alex
Try using through the following sytax...
match "contact_infos/:id/edit" , :to => "contact_infos#edit", :as => 'contact_infos_edit'
Please note that whilst not part of your question, that a catch all route is a very bad idea.
This has been considered dangerous for some time, and is not recommended. It will allow the app to respond to actions for all HTTP methods (e.g. GET for things which should really be PUT). This exposes you to CSRF attacks, as the CSRF token is only required for PUT, POST and DELETE requests..
You should always explicitly route using the routing helpers for all resources you're making available, to ensure the app will only respond to correct requests (e.g. DELETE request for a destroy acttion)
Dumb question but I have some lingering confusion of what, exactly, a "resource" is in Rails. The term is used everywhere but I get a funny feeling it might be being used rather loosely. It's referenced in the model, the controller and, quite literally, in routes.rb.
Is it the specific route? For example, map.resources maps the 7 RESTful "resources". So an example of one resource would be the call to, say, the index action of a particular class's controller?!?
Is it a reference to the whole page/object being retrieved? or perhaps, more narrowly, a database table? or the row being retreived?
Is it something else?
Anyway, hopefully someone can set me straight...
Any object that you want users to be able to access via URI and perform CRUD (or some subset thereof) operations on can be thought of as a resource. In the Rails sense, it is generally a database table which is represented by a model, and acted on through a controller.
For example, you might have a User resource (with a users table in your DB). This is represented by a User model, is mapped to users_controller with map.resources :users (which then generates routes like /users (a collection of User resources) and /users/1 (a specific User resource).
You act upon those resources by using the appropriate HTTP method when making calls to those resources. POST to the resource collection (/users) creates a new record; GET retrieves a list of resources (/users) or a specific user (/users/1). PUT updates a specific user (/users/1/), and DELETE destroys that user. The URLs are the same, but the result (and controller action) may be different based on the HTTP verb. The idea, though is that /users/1 always means "I'm interacting with the User that has ID #1", regardless of the action.
Here's a good article discussing how most developers think that "Resource" is synonomous with the database table, the argument, I guess, being that mapping to the resource is mapping the controller to that database table (or, with ActiveResource, to another REST url).
Basically, I think a "resource" is "persisted data." map.resources maps the 7 RESTful actions to a particular suite of persisted data.
But I haven't thought about it too much in depth. Good question!
I think they probably mean it in the general web sense, i.e., Resource (Web):
the referent of any Uniform Resource Identifier
I don't think it has anything to do with database tables.
open your model folder, that is a hint of what resources you have!
example: users, pictures, comments...
A lot of people here say that resources refer to the database tables you have. It might be true sometimes but not necessarily true always. I could give you a lot of examples where you don't have a corresponding table in your database for a particular resource. Hence asssociating it with tables is rather wrong.
I would define a resource as a route which maps to related requests. So instead of declaring separate routes for the actions you want to do you can simply declare them using a resourceful route.In Rails, a resourceful route provides a mapping between HTTP requests and URLs to controller actions.
So say you define resources :users in config/routes.rb. You can now use a number of helpers to the controllers in your application like edit_user_path which returns users/edit .
Here's a good link: https://api.rubyonrails.org/v5.2.1/classes/ActionDispatch/Routing/Mapper/Resources.html
Which basically says: 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:
resources :photos
How would i go about routing www.homepage.com/site/about to www.homepage.com/about for example? I still would like to use "site" as a controller, I just want to remove it from the route.
On a separate note, ss this how you usually setup routes for pages like about and contact that appear right after the site name?
For the first question, you could put something like this in your routes.rb:
map.about '/about', :controller => 'site', :action => 'about'
As for the second question, i don't quite undestand it, can you be a little more specific?
On a separate note, ss this how you usually setup routes for pages like about and contact that appear right after the site name?
If you follow the principles of REST (and you probably should), then by and large every URL should be terminating in a "resource" (ie: a noun, a "thing"). Each resource in turn has a controller, and these controllers have a standardized and limited set of actions.
This is a bit different from the "classic" routing scheme, where a controller would have more varied actions (and thus you could lump more functionality into a single, larger controller)
So, for example, in a RESTful system:
/contact would map to a ContactController, and not a "contact" action in some other controller (as it could in classic routing)
/about would similarly map to an AboutController.
/site/about would map to an AboutController, but this would be a "nested" route under the Site namespace. If you want to get hardcore about the nesting (and I typically do), I would:
Put AboutController in the Site module (thus Sites::AboutController), which in turn is stored in the file /app/controllers/site/about_controller.rb
Create a SiteController
Map /site to SiteController
If you had a preexisting Site:AboutController mapped to /site/about and you wanted to remap it to /about, you could do so using #rbaezam79's method. However, I'd seriously consider relocating and renaming the class itself just for consistency.
All of the resources I listed above would probably be considered "singleton" resources. This means:
you use map.resource instead of map.resources to map your routes
the default action is "show" (and not "index" as it is with non-singleton resources). Typically this will be the only action you need. (You wouldn't ever want to create or delete your about page, would you?)
the names are typically singular instead of plural. (Although I've run into some stumbling blocks with this)
When setting up routes like this, be sure to run the command "rake routes" regularly; this will show you exactly what you're getting at any given time.