Forum: Ruby on Rails Modifying the default to_xml

44261b1dd4d1f942a43d19c45e3a22e4?d=identicon&s=25 AdamV (Guest)
on 2008-05-27 17:39
(Received via mailing list)
Hey all,

I've been struggling with the default way that rails generates XML
representations of things. Specifically, I have a tableless model that
I use to handle my searches (they return more than simply a collection
of results). I was struggling with this until I remembered that I can
simply use action.xml.builder to create my specific XML
representations.

However.

I'm not sure that I want to do this for all my ActiveRecord models.
I'd much rather modify the default way that the to_xml works, or even
creating a new to_adams_xml (or something) and configure my
controllers to use that.

But I'm not at all sure how I should go about doing that. Can someone
point me at some tutorials that will give me some hints as to where I
need to head?

Thanks!
Adam
2d8132658d56e51f19ace1c68e48b6aa?d=identicon&s=25 Thorsten Mueller (thorsten)
on 2008-05-27 17:41
why not simply overwrite the to_xml method?
44261b1dd4d1f942a43d19c45e3a22e4?d=identicon&s=25 AdamV (Guest)
on 2008-05-27 18:15
(Received via mailing list)
On May 27, 8:41 am, Thorsten Mueller <rails-mailing-l...@andreas-
s.net> wrote:
> why not simply overwrite the to_xml method?

That's the obvious approach; I should have used "Overwriting to_xml"
as my subject.

My real question, which I wasn't clear about, is really, "given that I
want to overwrite the to_xml for ActiveRecord, what is the best way to
do this?"

I could create a to_xml for each of my models but that begs the
question, why not simply use an action.xml.builder view? Indeed, I
think that would be the appropriate place to do it.

I'm looking to make the change to ActiveRecord itself. There are
probably a dozen ways to do it but I want to know the best way.

So I'm not really asking, "what should I do?" but rather, "how should
I do it?"

Adam
D0cd6b10e01bacb976b3b815a9c660bc?d=identicon&s=25 Alex Wayne (squeegy)
on 2008-05-28 05:22
AdamV wrote:
> On May 27, 8:41 am, Thorsten Mueller <rails-mailing-l...@andreas-
> s.net> wrote:
>> why not simply overwrite the to_xml method?
>
> That's the obvious approach; I should have used "Overwriting to_xml"
> as my subject.
>
> My real question, which I wasn't clear about, is really, "given that I
> want to overwrite the to_xml for ActiveRecord, what is the best way to
> do this?"
>
> I could create a to_xml for each of my models but that begs the
> question, why not simply use an action.xml.builder view? Indeed, I
> think that would be the appropriate place to do it.
>
> I'm looking to make the change to ActiveRecord itself. There are
> probably a dozen ways to do it but I want to know the best way.
>
> So I'm not really asking, "what should I do?" but rather, "how should
> I do it?"
>
> Adam

Doing a to_xml on an active record object straddles a blurry line beween
data and presentation.  The simple answer is to just make a new to_xml
method on everything that needs it.  You can actually use builder
outside of a view.  I would do this:

  def to_xml
    returning '' do |output|
      xml = Builder::XmlMarkup.new(:target => output, :indent => 2)
      xml.foo {
        xml.bar "Foo and Bar make FooBar"
      }
    end
  end

The trouble is that the way rails works, template renderers are not
available everywhere.  So you can't do this:

  def to_xml
    render :partial => 'thingy.xml', :locals => { :thingy => self }
  end

Although that might be cleaner.  The other approach is a presenter
object.  I'm not too familiar approach, but a presenter cleans up the
model -> view interface.  Things like an XML view would reside in a
presenter for that model.  That is then presented to the view for
rendering, without adding noise to your models.  But one way may look
like this:

  def presenter
    @presenter ||= Thingy::Presenter.new(self)
  end

  def to_xml
    @presenter.to_xml
  end

Your presenter can then handle retrieving other view-centric data.  If
you create a method on your model, that you only use in the view, then
that would probably be a good presenter method.

But, really, you are probably fine just using Builder directly in your
model.
44261b1dd4d1f942a43d19c45e3a22e4?d=identicon&s=25 AdamV (Guest)
on 2008-05-28 06:45
(Received via mailing list)
Maybe if I explain myself a bit better, I 'll get some more feedback
from people.

I've been thinking a lot about what a restful interface should look
like and I've been primarily looking at Rails' implementation. As I've
been thinking about it, and looking at Roy Fielding's talk on the
subject, I think that there is something missing with the XML
serialization in rails. This is based on my observations of how Rails
seems to be creating its XML representations.

The issue concerns associated objects; the has_many and belongs_to
crowd. According to my understanding of Roy's presentation (I'll read
his dissertation, I promise), a representation of a resource exposes
its associated resources through its URL.

Let me give an example. Lets say I have the following models:

class Blog < ActiveRecord::Base
  belongs_to :author
end

class Author < ActiveRecord::Base
  has_many :blogs
end

Assuming that these are both resources, you'll get something like:

# GET /blogs/1.xml
<blog>
  <id type="integer">1</id>
  <name type="string">My Blog</name>
  <author-id type="integer">1</author-id>
</blog>

# GET /authors/1.xml
<author>
    <id type="integer">1</id>
    <name type="string">Adam</name>
</author>

From Roy's presentation I think that the "REST Way" to do things would
be more like:

# GET /blogs/1.xml
<blog uri="http://rest.example.com/blogs/1.xml">
  <name type="string">My Blog</name>
  <author uri="http://rest.example.com/authors/1.xml" />
</blog>

# GET /authors/1.xml
<author uri="http://rest.example.com/authors/1.xml">
    <name type="string">Adam</name>
    <blogs>
        <blog uri="http://rest.example.com/blogs/1.xml" />
        <blog uri="http://rest.example.com/blogs/7.xml" />
        <blog uri="http://rest.example.com/blogs/123.xml" />
    </blogs>
</author>

I might also put the URI in an element but this way seems a lot more
compact. Besides, the URI is really metadata in this sense.

I think that this approach has a number of advantages. First is
polymorphism. Not that it wouldn't be challenging for your framework
to handle but the following member representation seems very
compelling (I'm going to skip the type attributes as I think they're
tedious for examples):

<member uri="http://rest.example.com/members/1.xml">
    <name>Jim Bob</name>
    <subscriptions>
        <subscription uri="http://rest.example.com/blogs/1.xml" />
        <subscription uri="http://rest.example.com/galleries/
2132.xml" />
    </subscriptions>
</member>

I've represented a polymorphic association without having to express
what types the members are. I can determine that when I retrieve the
associated representations.

The second advantage is crossing the domain boundary. I was thinking
that it might be nice to refer to members by their Open ID uri but I
suspect that might not be a good example. However, we might extend or
previous example a bit:

<member uri="http://rest.example.com/members/1.xml">
    <name>Jim Bob</name>
    <subscriptions>
        <subscription uri="http://rest.example.com/blogs/1.xml" />
        <subscription uri="http://rest.example.com/galleries/
2132.xml" />
        <subscription uri="http://groups.google.com/group/rubyonrails-
talk" />
    </subscriptions>
</member>

Depending on what is consuming your API that may or may not be
problematic. I wouldn't see a problem with this if I was building a
JavaScript application to consume the XML. Perhaps if you could
associate an ActiveResource with an XML Schema rather than a URL, this
would be feasible in Rails.

Since not all associated objects are made into resources (for instance
join objects for has_many :through), those associations should be
realized directly in the XML representation (I believe the :include
option does this now).

So back to my questions. I want to be able to do all this without
having to create view files for each model I create. Instead I want to
create a plugin that modifies how to_xml works to give me the
behaviour I want. The only problem is that I'm having a hard time
getting my head around which methods of which classes I need to
override to get all this to happen.

Thanks!
Adam
44261b1dd4d1f942a43d19c45e3a22e4?d=identicon&s=25 AdamV (Guest)
on 2008-05-28 07:57
(Received via mailing list)
On May 27, 8:22 pm, Alex Wayne <rails-mailing-l...@andreas-s.net>
wrote:

Clearly, you finished your reply before I finished my elaboration.

Thanks, that will help a lot.
Please log in before posting. Registration is free and takes only a minute.
Existing account

NEW: Do you have a Google/GoogleMail, Yahoo or Facebook account? No registration required!
Log in with Google account | Log in with Yahoo account | Log in with Facebook account
No account? Register here.