New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Patch verb #505
Patch verb #505
Conversation
PATCH is the correct HTML verb to map to the #update action. The semantics for PATCH allows for partial updates, whereas PUT requires a complete replacement. Changes: * adds the #patch verb to routes to detect PATCH requests * adds #patch? to Request * adds the PATCH -> update mapping in the #resource(s) routes. * changes default form helpers to prefer :patch instead of :put for updates * changes documentation and comments to indicate the preference for PATCH This change tries to maintain complete backwards compatibility by keeping the original PUT -> update mapping. Users using the #resource(s) routes should not notice a change in behavior since both PUT and PATCH requests get mapped to update.
Make :put the default method for backwards compatibility. The generator for new Rails projects configures :patch a the default method in config/application.rb.
|
GitHub needs a +1 button. |
|
I googled for HTTP verbs and clicked the first result and PATCH isn't listed. http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html Where is it? Also I hardly think that updating everything except the primary key and the |
| # | ||
| # Example: | ||
| # | ||
| # patch 'bacon', :to => 'food#bacon' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The example needs to be indented 2 spaces so it'll show up correctly in the docs.
|
@josevalim, @fxn: Hey guys, this pull request has been sitting here for over a month unnoticed. It seems like master is now hosting code for Rails 3.2, so I'm thinking it can be merged in? |
|
It seems fine for me with the view configuration option. I am a bit concerned about generating more routes (routes generation is already slow), but I don't consider it a blocker at first. /cc @NZKoz |
|
Yes I had it in mind, but waiting for 3.1 to start working on 3.2 proper. |
|
Just a ping to say I am still waiting for 3.1 and have not forgotten this patch. That's because albeit 3-1-stable is branched, I prefer a master that does not move too much because cherry-picking back to 3-1-stable is very common these days. Focus is 3.1 now. The patch does not merge cleanly anymore, by the way, in case you want to maintain it in sync. |
|
@fxn, cool, glad to know this hasn't been forgotten. Let me know when you're ready to merge so I can update the pull request. |
|
Nice patch! I think this will break apps (and engines) that use explicit |
|
+1 from me. I wish GitHub had a better way to subscribe to issues instead of just commenting. I feel like "+1" is just noise, but I want to see what happens with this pull... |
|
@steveklabnik can't you just click the 'Enable notifications for this Pull Request' link at the bottom? |
|
@steveklabnik test clicking in the link at the end of this page: Notifications for new comments on this Pull Request are off. Enable notifications for this Pull Request @jeremy This one is candidate for Rails 3.2 or 4.0? |
|
3.2 candidate for sure. This needs thorough attention for a clean upgrade, however. The guides need closer attention. Perusing the diff, I see a lot of search/replace changes from PUT to PATCH. I think having PUT just disappear will be too confusing. Gotta explain this change each step of the way! Anyone care to take up the torch on this? |
|
i must be the only person in the world that disagrees with "PUT requires a complete replacement", as per RFC2616 "HTTP/1.1 does not define how a PUT method affects the state of an origin server" that said i like the name PATCH better than PUT for the purposes of what it is used for here. |
|
I can refine this patch if the core team decides it will definitely go into Rails 3.2... don't want to write another huge patch just to be pushed off to the next version :). @jeremy can you give an example scenario where the |
|
Yes, we talked about this patch after 3.1 and it is in the "roadmap" for 3.2 if it is good to go by then. @stevegraham RFCs are not axiomatic systems, but I think there's no controversy in that PUT means "put this resource at that URL" ("The PUT method requests that the enclosed entity be stored under the supplied Request-URI."). You're sending the resource itself, and in the target URL you either create a new resource ("If the Request-URI does not point to an existing resource, and that URI is capable of being defined as a new resource by the requesting user agent, the origin server can create the resource with that URI."), or else replace the existing one ("If the Request-URI refers to an already existing resource, the enclosed entity SHOULD be considered as a modified version of the one residing on the origin server."). It is the app's choice to conform to that spec. Nowadays to do partial updates in a RESTFul way you need to define ad-hoc resources. For example, to toggle the "paid" flag of an invoice you may PUT to /invoices/:id/paid, but if you play by the rules you need PATCH for partial updates to /invoices/:id. |
|
Aside the docs concern, this pull request looks good to me. I would just add the following changes (but I can do it myself in later commits after this is merged, this is more of a mental note):
|
| @@ -312,6 +312,11 @@ Rails will also automatically set the +class+ and +id+ of the form appropriately | |||
|
|
|||
| WARNING: When you're using STI (single-table inheritance) with your models, you can't rely on record identification on a subclass if only their parent class is declared a resource. You will have to specify the model name, +:url+, and +:method+ explicitly. | |||
|
|
|||
| NOTE: Rails can use the +PATCH+ method instead of +PUT+ for update forms if you set the following option in your +config/application.rb+: | |||
| <ruby> | |||
| config.action_view.default_method_for_update = :update | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo: should be = :patch.
|
@stevegraham I have found a crystal clear and authoritative answer to whether PUT allows partial updates: The very RFC 5789 (http://tools.ietf.org/html/rfc5789) states that "A new method is necessary to improve interoperability and prevent errors. The PUT method is already defined to overwrite a resource with a complete new body, and cannot be reused to do partial changes." |
|
I like the idea of moving this to be config.action_view.default_method_for_update as it lets people who care about these things choose to use patch without hitting anyone with 2x route proliferation. However I'm pretty strongly opposed to switching the default to PATCH just because of a neurotic interpretation of the RFC. There are people with blog posts, printed books and screen casts where they do Or Switching the default will make all of those tutorials and chunks of code fail with routing errors, and "the RFC says X" doesn't seem like anywhere near a good enough reason to do that. Maybe for a 4.0 change but absent some genuine bug or difficulty we can't do this in a random minor release. |
Yeah, sure, I mean, the asset pipeline from 3.0 -> 3.1 was a waaaaaaay smaller change. ;)
This is not neurotic. It's simply following the way that things are supposed to work. Many more people want partial updates than an upsert, that's what PATCH is. |
|
@dlee see my previous comment for a concrete example |
|
@jeremey I was actually responding to your first comment in this thread. You say that explicit |
|
@dlee Declare a resource in config/routes. Declare a Not the end of the world, and docs should be enough to cover that. |
|
@jeremy One of the points of the change was:
Note that form helpers use :patch only for new apps. Would this still not cover that case? |
|
@mikekelly we have not outlined yet the path, as I said before I don't expect to do any dramatic changes any time soon. Let's explore. At this point in the thread, the conclusion is that we are going to add some support for PATCH and promote good practices regarding PUT/PATCH in Rails applications. Good practices as described by Roy Fielding. But progressively, and with backwards compatibility as a must. At least for the time being. |
Ok fair enough, in that case it looks like @NZKoz hit the nail on the head over a month ago.. #505 (comment) |
|
The point of following the discussion was to know whether we should have to add anything at all. At that point we didn't know. If Roy said "yeah, just do partial updates with PUT" no flag should be added, no code should be in core. If Roy says "PUT means PUT. There are no partial updates in PUT." that justifies working on the PR. Working on the PR means what I said above, it does not mean applying the very patch. |
|
Allowing access to PATCH as a configuration option will help drive awareness and adoption. Further down the line, we might well see a larger number of devs and applications clamoring for a change of default configuration, in much the same way we saw jQuery make its way in core. Count this as +1 to a configuration option. |
|
Rails 4 has been announced for the summer. How much PATCH support should we get in? There have been various proposals of how to support PATCH in Rails 4:
|
|
@dhh mentioned on Twitter that he supports some kind of support. Really, to be honest, I think this pull request should probably be closed, and a discussion thread should be made on rails-core about it. That's sorta out of the scope of this particular PR. |
|
We should have a config option called |
|
In other words, this pull request is almost good imo. It just needs to provide a |
|
@josevalim It really depends on how far you actually want to go. A 'rails 4' gives a big opportunity to step back and evaluate the whole 'Rails REST' thing in general. Then again, it seems that rails core wants rails 4 to be more of a normal release, so... Regardless, I agree about this patch. It's good regardless of that stuff. |
|
If Rails core gives the OK, I can fix the patch according to @josevalim's recommendations. |
|
PATCH and PUT have different semantics. PUT means create/replace and it is idempotent. PATCH means update (full or partial) and it is not idempotent. If your application is a s3 clone, you want to upload assets with PUT. I think we need to be able to have both working, rather than a exclusive option. |
|
@fxn I agree both options should work, it is just a matter of what we choose as default. For instance, the router should generate just put or patch routes by default for resources, however if for some specific case I want to use both PUT and PATCH or another, I should be able to do it. The same for the view, responders, etc... they should work for both put and patch. |
|
I hinted at this above, but to reiterate: besides changing rails so that it supports PATCH, I'd also like to see improved support for proper PUT semantics. Currently, rails idioms and conventions do not make this easy. Specifically:
Would the rails core team by interested in the addition of this API? I'm willing to take a stab at it, and can open another ticket to discuss further details, but figured it was worth inquiring here first. |
|
I like that idea; it'd make adhering to HTTP much easier. I'd prefer a method name that more strongly indicates the full-resource replacement. What do you think about |
|
If there would be a method, I would simply call it In other words, |
|
You bring up good points, @josevalim. I agree that people tend to think "model == HTTP resource" (or not even really think in terms of HTTP resources) and That said, rails doesn't currently have anything that helps make it easy to implement proper PUT semantics. If you want to implement proper PUTs you are essentially totally on your own. Do you have a better suggestion? (Also, should we take this to another thread? I don't want to derail the discussion here, but it's certainly related). As I see it, |
|
How Rails doesn't provide anything? Rails is a framework, anyone can provide his own PUT setup according to his application semantics, as you did. And probably in less than 30LOC! Please start a new discussion as I have no interest in the direction this is going. |
|
Yeah, me neither. Resources are conceptual, ARs model database tables. There's a gap there that I think would show as a complicated setup for such a simple thing. I prefer to discuss that in another issue or PR. |
|
@josevalim and @fxn: no need for another ticket. Two core rails members have weighed in against the idea. Thanks for the input. That's one less open source contribution I need to worry about; I have enough on my plate as it is. |
|
#5130 merged. |
|
In the risk on being pedant by arguing on a closed discussion against the last three comments (@josevalim, @fxn and @myronmarston), where I even haven't any personal use case yet, I will still make my point here, since I don't know where it goes better. Rails does not provide a clean way to map resources to models "to and fro", which makes josevalim's point somewhat valid. I mean, devs usually call a model into a variable (normally in the controlle's show method), but they might as well make a mix of some related models to represent the resource that they want to expose. In this second case, they then have to rip the params off in the update action, so that they get the different models to validate and save and so on. That's what I see as a weak part of the framework. I feel that josevalim's argument could backing up a kind of "presenters-and-back" as a best way to translate/map models into resources, and that the implementation of such a paradigm into Rails should be seriously weighted. Were they dismissed (which I suppose, for that is a whole subject in itself), I would then come to my conclusion: I dislike disregarding a new method called See my point? I know I am a bit sarcastic at giving reasons for my petition, but I do it just in order to make it crystal clear and avoid another six months of discussion on the need of such method. I hope I got it. PS. Sorry for coming in so late, I just saw the thread linked in the Rails Blog. I got through the whole of it, oh my! |
|
I elaborated a bit more on the subject of ResourceAccessor and how and why the |
|
fwiw, I backported the HTTP PATCH verb work for Rails 3.2 https://gist.github.com/bf4/8940203 |
|
Hi @bf4, Your patch doesn't work with my app. Rails 3.2.22.5 It crashes when running the web server with the following error:
When running 'rake routes'
Any help will be greatly appreciated. |
Update: as ncreuschling points out, there was a typo in the pull request message that said "HTML verb" instead of "HTTP verb".
Updated: update forms default to PUT instead of PATCH for current apps. Defaults to PATCH for new apps.
PATCH is the correct HTTP verb to map to the #update action. The semantics for
PATCH allows for partial updates, whereas PUT requires a complete replacement.
Changes:
This change tries to maintain complete backwards compatibility by keeping the
original PUT -> update mapping. Users using the #resource(s) routes should not
notice a change in behavior since both PUT and PATCH requests get mapped to
update.