delete method in Rails - ruby-on-rails

What's the difference between delete and destroy?
If we generate a scaffold, the default method to remove an date entry is method: :delete, while delete is actually not defined in the controller. So how does rails actually figure out what to do?

DELETE is HTTP verb while destroy is an action in the controller. If you use resources in your application, HTTP DELETE requests are routed to destroy action in the controller (unless you change the default behaviour).
method: :delete in link_to options means that clicking a link would trigger HTTP DELETE request.

As far as I know:
Delete method uses an SQL DELETE statement without instantiating the objects or running any callback.
Destroy makes the SQL call to the database and deletes the row in the table where the current object is contained, you can still manage the object as long as you have it scoped.
Hope this helps.

Related

In rails is 'method:' parameter used only for delete action?

I am new to Rails and came to know about the destroy action.When we write a destroy action for deleting something, in the link to delete it, we write the code:
method: :delete
So is the method parameter used only for delete, or is it used somewhere else too?
Thanks in advance.
By default (Incase if you don't mention method type) it take HTTP method type as GET
So explicitly for any other HTTP request you need to mention HTTP method type for request.
Destroy action(which is use to delete some record) should be delete type HTTP request. so in link it need to mention method: :delete otherwise it serve request as get. hopefully this will clear your doubt.
References: -
https://guides.rubyonrails.org/routing.html
https://guides.rubyonrails.org/v2.3/routing.html#restful-routes

Why does the rails scaffold use respond_to blocks in the create, update and destroy actions?

From what I understand, these actions are usually triggered after a form is submitted. I can't imagine any reason why a form would generate json, in other words, (assuming a hypothetical controller is named 'UsersController') I can't imagine when or how a form would take my browser to:
localhost:3000/users.json
wouldn't post requests automatically take the user to:
localhost:3000/users
...and hence automatically to html? And furthermore, if they arrived here, at:
localhost:3000/users
and typed in:
localhost:3000/users.json
wouldn't this just be a GET request back to index.json? And hence back to the index action?...rendering json in that particular action via a GET request (not the create action, via POST)?
I'm confused and can't understand how anyone could ever end up at users.json from a POST request, and hence I can't imagine why a respond_to block that renders json makes sense in these actions. What am I missing?
Rails assumes that the controller actions might also be accessed as an API and not just via the browser. In such cases it makes sense to respond to those requests differently instead of redirecting the client (browser) to the index or show action.
When you create a resource from an API client, it might not make sense to redirect the user to the index or show action instead of just responding to the client that the resource was created (or not). Same applies for the update and destroy actions.

Why doesn't direct path for delete/destroy exist in rails?

When you define a link_to in rails to delete an object/item you must specify method delete in that link_to, as compared to edit (edit_event_path(#event)) or show (event_path). Why is this the case?
In typical link_to links the browser will send HTTP GET requests. When you're destroying a resource the browser should send a HTTP DELETE request. Rails has some javascript that will run on those links and intercept the click to send a HTTP DELETE request for those marked with method: :delete. Also the path for a single resource to be destroyed and shown will be the same.
event_path will return "/event/1" or similar. When sending a HTTP GET request its expected that the show action of your controller will be called. When sending a HTTP DELETE request to the same path its expected that the destroy action will be called.
HTTP Verbs
Simply, Rails makes use of the HTTP Verbs which governs the web
Essentially, to keep routing structures simple, Rails allows you to generate a series of the "same" URL paths, each defined with different http verbs:
This means if you want to destroy an object, you can use the delete verb
--
OOP
A more specific definition for this lies with the object-orientated structure of Ruby (& Rails). The routing system is based around this structure (hence why they're called resources) - meaning if you treat the routing system as based around objects, you can begin to see a pattern emerge
If you're going to call a route for an object, IE to destroy that object, your route should be for the "object", not the "destroy" mechanism
In this sense, if you want to destroy an object, it makes much more sense to use the following:
<%= link_to "Destroy", object_path(object), method: :delete %>
This gives you the flexibility to create actions around objects, which can then be routed to the particular controller#actions as required

how to hit a put route

I have an additional method in one of my otherwise restfull controllers called 'importdata'. As I'm actually changing the data (importing csv in the database), I understood that it should be a put route instead of get.
Initially I had
resource data_set do
put 'importdata', on: :method
end
what I also tried is:
put 'data_sets/:id/importdata', "data_sets#importdata'
rake routes shows the route I want in both cases.
What I did when I had the method on (1st example) route in the controller was
redirect_to import_data_sets_path id: dataset.id
And with the second example:
redirect_to controller: "data_sets", action: "importdata", id: dataset.id
The message I get in both cases is:
No route matches [GET] "/data_sets/28/importdata"
Which is correct, because it's a put route. The only way I get this to work is to change the put for a get:
get 'data_sets/:id/importdata', "data_sets#importdata'
How can I get that to work on a put route? Should it be a put route in the first place?
Thanks for your time.
Simply put you can't 'upgrade' a HTTP request issued by an user. redirects only work over GET. If the user is changing something do it through a form and make sure it's a PUT request as you're modifying an existing resource.
If the PUT is conditional there's several options, either figure out how to solve this in the UI, use an HTTP client to issue the PUT(which doesn't make sense for an local call) or extract the editing of the resource in some other kind of class and use it in the controller.
However, even if the edit is optional it makes more sense to let the user fire a PUT in the first place.
Hope that helps.

Is there any harm in using a typical GET action for a PUT? (RESTfully speaking)

I have an action that doesn't require a form. So it really only needs the one 'edit' method instead of the RESTful 'edit' --> 'update'. Is there any reason not to do this or a better way?
def edit
#Do a POST(PUT)
end
The harm is that a user could easily navigate to that url and perform a potentially destructive action.
/noform/edit #URL typed by user => Action Performed
/noform/update #URL typed by user => Error is thrown, No Action Performed
A normal browsing experience generates GET requests to the server. The assumption is, any page you can easily navigate to (or type into your address bar) will not perform any data changing functions.
A POST request, generated via a form submission or a AJAX request expects the result that data is changed on the server.
Similarly the two rails "faked" versions of PUT and DELETE also are not actions you could simply navigate to using a browser.
The solution
The solution is to have only the update action and where you originally would have linked to edit use something like the following:
button_to "Add new tracker", noform_path, :method => :put
If there is any type of error, you may still need an edit path to show the user so they can correct something. But from what you have described, a single update action should do the trick.
Gets should always be idempotent -- that is they should not perform any action that will alter the state of the application, database, etc.
Just as an aside -- in true RESTful form an edit would be performed by an HTTP Update action, but Rails simulates this with a post and a hidden value on the form, since browsers don't have HTTP Updates.
It's still not clear to me why you need an update without an input field. Perhaps a little more detail would be helpful.

Resources