views:

1311

answers:

4

I'm curious about people's experiences using AR's to_xml() to build non-entity fields (as in, not an attribute of the model you are serializing, but perhaps, utilizing the attributes in the process) from a controller.

to_xml seems to supply a few options for doing this.

One is by passing in references to methods on the object being acted on: during the serialization process, these methods are invoked and their results are added to the generated document. I'd like to avoid this path because some of the generated data, while depending on the object's attributes, could be outside of the scope of the model itself -- e.g., building a URL to a particular items "show" action. Plus, it requires too much forethought. I'd like to just be able to change the resultant document by tweaking the to_xml code from the controller. I don't want the hassle of having to declare a method in the object as well.

The same goes for overriding to_xml in each object.

The other two options seem to fit the bill a little better: one is by passing in procs in the serialization options that generate these fields, and the other is by passing in a block that will yielded to after serialization the objects attributes. These provide the kind of at-the-point-of-invocation customizing that I'm looking for, and in addition, their declarations bind the scope to the controller so that they have access to the same stuff that the controller does, but these methods seem critically limited: AFAICT they contain no reference to the object being serialized. They contain references to the builder object, which, sure I guess you could parse within the block/proc and find the attributes that have already been serialized and use them, but that's a harangue, or at least uneasy and suboptimal.

Correct me if I'm wrong here, but what is the point of having procs/blocks available when serializing one or more objects if you have to access to the object itself.

Anyway, please tell me how I'm wrong, because it seems like I must be overlooking something here.

Oh and yeah, I know that I could write my own view. I'm trying to leverage respond_to and to_xml to achieve minimal extra files/lines. (Though, that is what I resorted to when I couldn't figure out how to do this with AR's serialization.)

**EDIT 3.29.09 -- I just submitted a patch for this to Rails. If you're interested, show some support :) https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/2373-record-sensitive-procs-for-to_xml

+1  A: 

Actually the Proc is passed the same options hash (minus the procs option) you passed into to_xml. So you can pass in any extra objects the Proc needs to do it's job:

proc = Proc.new {|options| options[:builder].tag!('reverse-name', options[:object].name.reverse)}
object.to_xml :object => object, :procs => [ proc ]

Since you're getting the proc is getting the same options to_xml is, this is allows you to pass in whatever options you need.

Patrick Ritchie
So in your example here "object" is an extra k/v pair that you are using which will be passed on to each serialization call and proc. That's good. It certainly creates possiblities. The challenge remains: how would you do this on an array? Pass in the array as an extra k/v and iterate in tandem? :/
greenagain
A: 

What if I want to use a proc in an array of objects. I'd like to call proc on an individual attribute. Lets say I have @contacts and am trying to .to_xml it. I want a proc to access a single contact, so that it is run through each contact. How will proc know which contact it's being called on?

A: 

Has anyone figured out how to do this for an array? Basically what matt asked above.

I found a straightforward way for the array case. Where you want the xml conversion to call extra methods for an array of things, for example in a format.xml block, replace this: render :xml => @thingswith this: render :text=> @things.to_xml(:methods => [:extra1, :extra2])
Jack Nutting
A: 

Woo! My patch to handle this scenario was accepted: http://github.com/rails/rails/commit/c39151a84768397d3bb025c6e8f877eac59ebbf9 It's a part of ActiveModel now, and I'm not exactly sure what the release schedule for that is; I'm thinking Rails 3.

greenagain