Gmail Calendar Documents Reader Web more »
Recently Visited Groups | Help | Sign in
Google Groups Home
Message from discussion ActiveRecord .from_xml upgrade
The group you are posting to is a Usenet group. Messages posted to this group will make your email address visible to anyone on the Internet.
Your reply message has not been sent.
Your post was successful
 
From:
To:
Cc:
Followup To:
Add Cc | Add Followup-to | Edit Subject
Subject:
Validation:
For verification purposes please type the characters you see in the picture below or the numbers you hear by clicking the accessibility icon. Listen and type the numbers you hear
 
Phlip  
View profile  
 More options Mar 7, 8:53 pm
Newsgroups: comp.lang.ruby
From: Phlip <phlip2...@gmail.com>
Date: Sun, 8 Mar 2009 10:53:21 +0900
Local: Sat, Mar 7 2009 8:53 pm
Subject: [ANN] ActiveRecord .from_xml upgrade
Rubies:

The gist of this tiny code snip...

    http://gist.github.com/75525

...is a light but flexible DSL that converts XML - typically output by to_xml()
- into an ActiveRecord object model.

==create or update records==

Here's the simplest example:

    xml ='<photos>
            <photo>
              <id>323285</id>
            </photo>
            <photo>
              <id>323310</id>
            </photo>
    ...
          </photos>'

    doc = Nokogiri::XML(xml)
    photos = doc.from_xml(Photo, :id)

(Note that from_xml{} is a member of a Node, not of your Model.)

That code created new Photo records with matching IDs. If any record were
already there, the code would update it instead.

==rename fields and pass in data==

Here's the next more complicated example:

    authors = node.from_xml(Author, [:id, :remote_id], :name)

The code reads an <id> tag, then finds or creates an author with a
matching author.remote_id. Then the code updates the author.name, and
return an array of authors.

==associations==

from_xml takes an optional &block, and yields into this the record under
construction, before its .save! call. Use this block to seek nested data, and
plug them into their parent record:

    doc.from_xml Post, :id, :title, :body do |post, node, *|
      post.tags = node.from_xml(Tag, :id, :name)
      post.author = *node.from_xml(Author, :id, :name)
      post.save!
    end

from_xml{} will call that block each time it finds a (top-level) <post> record,
and each nested node.from_xml{} call will only find records inside that main record.

(Note, also, that <tag> records, for example, should be shared between many
<post> records, and your XML will probably just duplicate them many times, but
from_xml(Tag) knows to fold them all back together again...)

The splat operator * threw away three more arguments - they were the string
values of the id, title, and body fields.

==raw XML==

To scan your XML with very similar abilities, but without using a Model with the
correct name to match your XPath, write the XPath directly into the lower-level
convert{} method:

      node.convert 'tags/tag', :id, :name do |n, id, name|
        tag = Tag.find_or_initialize_by_id(id)
        tag.update_attribute :name, name
         # or tag.attributes = n.data
        post.tags << tag
      end

That block shows form_tag{} "unrolled" into its low-level behavior. convert{}
takes an XPath query, relative to the current node, and a list of fields (and
their renamers) to extract. Then it yields the detected node (don't call it
"node"!) into its |goal posts|, with the string value of each detected field.

Your block could have done something more complex, but this one merely simulated
form_tag{} by reconstituting and updating a Tag record, then inserted it into
some outer post object.

One more detail - the renamed fields, and their string values, are also
available as a hash. To avoid even more extra arguments into our goal posts, the
committee stashed them into the passed node, as an attribute called "node.data".
So the little comment shows how to update all your Model attributes at once.

==what about to_xml?==

One ActiveRecord FAQ goes, "Why can't from_xml take the same arguments as
to_xml?" The reason is creation is harder than just reading an existing object
model. While a future version of from_xml{} could indeed learn to follow model
associations, and could take a big blob of nested hashes, like most other
ActiveRecord methods, the committee does not foresee this DSL exactly matching
the input to to_xml(). That is a goal for further research on both sides!

--
   Phlip
   http://www.zeroplayer.com/


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.

Create a group - Google Groups - Google Home - Terms of Service - Privacy Policy
©2009 Google