# ReST PUT with multiple records

**URL:** <https://www.ruby-forum.com/t/rest-put-with-multiple-records/118584>\
**Category:** Rails\
**Created:** [October 29, 2007, 7:46am UTC](https://www.ruby-forum.com/t/rest-put-with-multiple-records/118584 "2007-10-29T07:46:01Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![magpie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/45deac/32.png) [@magpie](https://www.ruby-forum.com/u/magpie)\
**Post date:** [October 29, 2007, 7:46am UTC](https://www.ruby-forum.com/t/rest-put-with-multiple-records/118584/1 "2007-10-29T07:46:01Z")

</div>

I’m writing a Flex/ReST/Rails app and I currently do a GET on  
/customers/123/licences.xml to get the licences for customer 123. This  
works fine. Now, after updating one or more licences, I wish to update  
(PUT) the licences back to the server.

Does this sound reasonable and restful ?

The problem is that map.resources doesn’t add a route for PUT on the  
index action, and I haven’t been able to figure out how to specify the  
method for a route. It does work to PUT a single licence to eg.  
/licences/456.xml

Many thanks for any assistance.

---

<div class="post-metadata">

**Author:** ![magpie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/45deac/32.png) [@magpie](https://www.ruby-forum.com/u/magpie)\
**Post date:** [October 29, 2007, 12:39pm UTC](https://www.ruby-forum.com/t/rest-put-with-multiple-records/118584/2 "2007-10-29T12:39:01Z")

</div>

Why not PUT the updated licenses one by one? This saves you a lot of  
trouble I think… for example, what to do if one of the 10 updated  
licenses will not save because, e.g., validation fails?

---

<div class="post-metadata">

**Author:** ![magpie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/45deac/32.png) [@magpie](https://www.ruby-forum.com/u/magpie)\
**Post date:** [October 29, 2007, 4:43pm UTC](https://www.ruby-forum.com/t/rest-put-with-multiple-records/118584/3 "2007-10-29T16:43:34Z")

</div>

On 10/29/07, Gerjan S. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> Why not PUT the updated licenses one by one? This saves you a lot of  
> trouble I think… for example, what to do if one of the 10 updated  
> licenses will not save because, e.g., validation fails?

Pretty inefficient when you can just slurp all the records in one  
request.

Make your create action know what to do when it receives a collection  
document instead of an item document. Or break REST a little bit and  
write a create\_many action. As far as handling errors goes, it  
depends entirely on what you need to do. You can run all the creates  
in a transaction and return an error code if one fails. You can run  
them all and make callbacks somewhere, notifying the source app that  
one of the creates failed.

Pat

---

<div class="post-metadata">

**Author:** ![magpie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/45deac/32.png) [@magpie](https://www.ruby-forum.com/u/magpie)\
**Post date:** [October 29, 2007, 7:34pm UTC](https://www.ruby-forum.com/t/rest-put-with-multiple-records/118584/4 "2007-10-29T19:34:29Z")

</div>

On 10/29/07, Pat M. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> document instead of an item document. Or break REST a little bit and  
> write a create\_many action. As far as handling errors goes, it  
> depends entirely on what you need to do. You can run all the creates  
> in a transaction and return an error code if one fails. You can run  
> them all and make callbacks somewhere, notifying the source app that  
> one of the creates failed.

I’ve thought about this some in my own app, from the desire to bulk  
import items via XML. Here’s my train of thought:

1. Create a custom rest method. map.resources :items, :collection =\>  
{:bucket =\> :post}

POST /items/bucket.xml # import

1. Depending on my needs, maybe I’ll want to validate the items and  
let the user verify before actually inserting them into the system.

map.resources :items do |item|  
item.resource :buckets  
end

POST /items/bucket.xml # import  
GET /items/bucket.xml # view current validated items  
PUT /items/bucket.xml # confirm and actually import items  
DELETE /items/bucket.xml # remove validated items instead of importing  
them

–  
Rick O.  
[http://lighthouseapp.com](http://lighthouseapp.com)  
[http://weblog.techno-weenie.net](http://weblog.techno-weenie.net)  
[http://mephistoblog.com](http://mephistoblog.com)

---

<div class="post-metadata">

**Author:** ![magpie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/45deac/32.png) [@magpie](https://www.ruby-forum.com/u/magpie)\
**Post date:** [October 30, 2007, 4:44am UTC](https://www.ruby-forum.com/t/rest-put-with-multiple-records/118584/5 "2007-10-30T04:44:59Z")

</div>

Thanks for the suggestions & discussion.

I’m toying with my own philosophy that any GET should be able to be PUT  
back.  
I store my GET as an XML node tree, the Flex controls modify this, then  
I put it back to its original URL. Currently this isn’t efficient as  
only one field in one licence may have changed, but there is potential  
for non-obtrusive optimisation if the XML nodes can track whether they  
or their children have changed.

I got the route by logging all routes to a file with :

def self.dump\_routes  
result = ‘’  
ActionController::Routing::Routes.routes.each { |route| result \<\<  
route.to\_s }  
end

and then modifying my routes until I got the desired output.

The result is now :

map.resources(:customers,{}) do |customer|  
customer.resources(:licences,{})  
customer.connect ‘/customers/:customer\_id/licences.xml/’, :controller  
=\> ‘licences’, :action =\> ‘index’, :format =\> ‘xml’, :conditions =\> {  
:method =\> :put }  
end  
map.resources(:licences,{})  
map.connect ‘licences.xml’, :controller =\> ‘licences’, :action =\>  
‘index’, :format =\> ‘xml’, :conditions =\> { :method =\> :put }

(and it works) for anyone interested.

I’m using a modified generic rest controller from  
[Google Code Archive - Long-term storage for Google Code Project Hosting.](http://code.google.com/p/restcontroller/w/list) and the index action  
looks like :

def index(options = @options)  
if request.method==:get  
@page\_title ||= 'Listing ’ + resources\_display\_name

```
  scope_find do
    resources_instance_set resource_model.find(:all, 

```

options[:find\_options])  
end

```
  respond_to do |format|
    format.html { render :action => options[:template] || 'index'}
    format.xml { render :xml => resources_instance.to_xml }
  end
elsif request.method==:put
  resourcelist = params[resources_name][resource_name] rescue nil
  raise RuntimeError("records not found") unless resourcelist && 

```

!resourcelist.empty?  
resourcelist = [resourcelist] unless resourcelist.is\_a? Array  
success = true  
errors = {}  
resourcelist.each do |aResourceHash|  
model\_instance = resource\_model.find\_by\_id(aResourceHash[‘id’])  
success = false unless  
model\_instance.update\_attributes(aResourceHash.filter\_include(resource\_model.column\_names))  
errors = model\_instance.errors  
break if !success  
end  
if success  
render :nothing =\> true  
else  
render :xml =\> errors.to\_xml  
end  
end  
end

magpie

---

<div class="post-metadata">

**Author:** ![magpie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/45deac/32.png) [@magpie](https://www.ruby-forum.com/u/magpie)\
**Post date:** [December 5, 2007, 2:43pm UTC](https://www.ruby-forum.com/t/rest-put-with-multiple-records/118584/6 "2007-12-05T14:43:37Z")

</div>

Yeah, except that the bulk importing doesn’t seem to work at all…  
because rails maps the bulk to params… and params is a hash, which  
as we all know means that the keys get overwritten with every update

(ie if we have a collection thus:)  
  
  
  
Yes!  
  
  
  
No!  
  
  
  
Maybe!

then our params looks like this:

params = {:blahs =\> {:blah =\> “Maybe!”}}

OMG what happened to the other two blah objects?

Well, they’re in the params hash, and unfortunatley it’s a hash, not  
an ordered array of arrays, and so we lost all our key overwrites.

What to do then, Rick?

I thought hmmmm maybe name the blahs

thus:

that’s ugly.

What do you reckon?

Julian.
