Question about PATCH method, accepts_nested_attributes_for, and updates to association lists (has_many, HABTM)

This is the reason that the spec for patch[1] specifically requires a diff be sent[2]:

The set of changes is represented in a format called a "patch document" identified by a media type.

and

With PATCH, however, the enclosed entity contains a set of instructions describing how a resource currently residing on the origin server should be modified to produce a new version.

and

Further, it is expected that different patch document formats will be appropriate for different types of resources and that no single format will be appropriate for all types of resources. Therefore, there is no single default patch document format that implementations are required to support.

If you plan to use PATCH, you should figure out what you need and use it. I'm not aware of a media type that does diffs in plain JSON at this time.

1: RFC 5789 - PATCH Method for HTTP 2: RFC 5789 - PATCH Method for HTTP

Steve,

Thanks for your response!

If you plan to use PATCH, you should figure out what you need and use it.

I had read: http://weblog.rubyonrails.org/2012/2/25/edge-rails-patch-is-the-new-primary-http-method-for-updates/

It states that:

Because of that, the PATCH method was defined in 1995 and standarized later. PATCH is a method that is not safe, nor idempotent, and allows full and partial updates and side-effects on other resources. In practice, as you see, PATCH suits everyday web programming way better than PUT for updating resources. In Ruby on Rails it corresponds naturally to the way we use update_attributes for updating records. Thus, PATCH is going to be the primary method for updates in Rails 4.0.

Rails supports use of accepts_nested_attributes_for to update associated models, so I’m curious how these patches could be accomplished easily in Rails 4:

  1. What would a JSON request look like that could be sent into a controller via patch method to only change one field in an associated model, where the model being updated accepts_nested_attributes_for the model that has the field you want to update?

  2. What would a JSON request look like that could be sent into a controller via patch method to only remove a single tie record to an association without changing the list of associations, to avoid losing other changes that have been made to the membership of the collection/list of associations? (Does patch require a _destroy on a tie/connecting model? If so, would that be bad terminology considering that changes to associations as pointed out in Active Record Associations — Ruby on Rails Guides for the Appointment tie models between Physician and Patient is deleted and not destroyed when there is a has_many :through relationship and the membership list is updated? In that case would a new _remove key on the associated model make sense?)

I’m basically just trying to understand what Rails 4 plans to offer with regard to patching, especially in the context of Javascript frameworks and the like that would be wanting to send/receive JSON to Rails controllers to manage not only models, but models and their associations. Just changing each model via its own request requires more requests and if there are changes that need to be made to specific fields of a model and specific fields of its associations in a single transaction, it would be much easier to just being able to send in a single patch request to a model that defines accepts_nested_attributes_for.

Thanks! Gary

I'm basically just trying to understand what Rails 4 plans to offer with regard to patching,

Here is the relevant commit: Add config.default_method_for_update to support PATCH · rails/rails@002713c · GitHub

The commit message gives a pretty decent overview. This is basically just a baby-step forward; but adding direct support for the method will allow other people to do exactly what they want.

Steve,

Thanks! I was under the impression that patch might actually allow patch updates in some planned future version of Rails 4 by only specifying attributes (and attributes of associated models through accepts_nested_attributes_for) that the client requests to update.

If everything is being directed to the update method and then it doesn’t support actually making patches, that seems like it would mislead more than it would actually provide desired functionality. I’m not suggesting PATCH be removed, but it would be nice if implementing patching behavior were on the roadmap. Should I put in a ticket for that?

If you are trying to do a patch, then JSON in the request could be easily converted to model representation in Rails. But just handling off the implementation of a patch to the developer leaves a lot up in the air.

For example, when parsing a patch, it would seem that there would be some way to differentiate between the incoming PATCH request specifying an attribute as nil vs. not specifying the attribute at all in the request (and therefore not wanting to set that attribute to nil). While this could be handled more simply, if you leave it up to the average developer, they might end up writing their own JSON parser and monkey-patching Object to add an “undefined” method to return some new Undefined class, so that it would appear to be part of syntax until an new type of nil could be added to Ruby called “undefined”, which would probably never be added… In other words, I think handling this sort of thing would be better done on the Rails side.

Gary

Should I put in a ticket for that?

This is exactly where feature requests go. So you kinda already did. :wink:

If you are trying to do a patch, then JSON in the request could be easily converted to model representation in Rails. But just handling off the implementation of a patch to the developer leaves a lot up in the air.

Yep. I've been giving some though to declaring some sort of 'Rails flavored JSON' that would be able to address these kinds of issues, but it's not near the proposal stage yet. We don't know what every application needs, so currently, it's left up to each dev.

For example, when parsing a patch, it would seem that there would be some way to differentiate between the incoming PATCH request specifying an attribute as nil

Again, this is the reason why PATCH requires a diff media type be sent to it. Then there's no question.

Steve, I’d be interested in this “Rails JSON media type” as well, but we can talk this weekend in Berlin. There is definitely a common behaviour that a lot of Rails projects would appreciate for a CRUD-style PATCH where the media type defines what will get overwritten, deleted, updated, also, with nested models, etc. Defining a media type would help Rails understanding that REST is not exposing a CRUD API through JSON.

Nick