consume! saves child collection objects when using ActiveRecord -- intended?

53 views
Skip to first unread message

JP Slavinsky

unread,
Jan 23, 2014, 5:24:12 PM1/23/14
to roar...@googlegroups.com
Howdy -

Reading around, it looks like consume! is intended to just make / update instances of objects but not to save them.  

Basing this statement on:


I thought a lot about the #consume! semantic and I decided it would be 
best to just do the setup process (e.g. filling the object with 
incoming data). Everything else, like saving and stuff is up to the 
user. That was to save us from having to write adapters for DM, AR, 
Sequel etc. 

and the roar-rails README:

The consume! call will roughly do the following.
singer.
  extend(SingerRepresenter)
  from_json(request.body)

But yesterday when I was consuming JSON representing a model and its contained collection of new model instances, I noticed that the model instances in the child collection were getting saved to database (using activerecord).  

It appears that this is because at some point in representable there is a call to set the has_many relation to the collection of newly instantiated objects, and in ActiveRecord when you have "aModel" persisted in the DB and then call aModel#collection=(array of instances) , the instances added to the collection are saved to the DB:

(http://guides.rubyonrails.org/association_basics.html
 
4.3.4 When are Objects Saved? 
 
When you assign an object to a has_many association, that object is automatically saved (in order to update its foreign key). If you assign multiple objects in one statement, then they are all saved. 
   ...
If you want to assign an object to a has_many association without saving the object, use the collection.build method 

 
Is this behavior expected or unexpected?  If unexpected but not easily fixable, might want to point it out in the README -- I had been working under the assumption that consume! wouldn't alter my DB.  

Ideas on a workaround?  If I open up some attr_protected fields I think I can use a setter in my collection definition:

class MyModel < ActiveRecord::Base
  has_many :items

with a decorator representer having the following collection:

collection :items
           ...
           setter: lambda do |value, *| 
                     items_attributes = value.collect{|v| v.attributes}
                     items.build(items_attributes)} # build wants attributes not objects
                   end

Other thoughts?  Addressable in roar-rails or representable?

Thanks - JP

Josh Cohen

unread,
Jan 23, 2014, 6:13:12 PM1/23/14
to roar...@googlegroups.com, roar...@googlegroups.com
I noticed this too.  I have been debating how/if my API should allow composite create/update of a parent/child resource. 

To my amazement, sending a post with an embedded collection created all of the objects. 

There is complexity in deciding if it should replace or append/modify too. 


Sent from mother device. Please excuse typos. 
--
You received this message because you are subscribed to the Google Groups "Roar" group.
To unsubscribe from this group and stop receiving emails from it, send an email to roar-talk+...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Nick Sutterer

unread,
Jan 23, 2014, 7:14:32 PM1/23/14
to roar...@googlegroups.com
You can use the parse_strategy: :sync option if you wanna update (but not save) an existing collection.

Also, we are working on several improvements for Roar/representable to introduce defined semantics for updating collections.

It seems an odd thing that the collection is automatically saved. However, this is a #from_json issue in representable, which is  simply called by #consume.
Reply all
Reply to author
Forward
0 new messages