Given this model (DataMapper):
class Article
include DataMapper::Resource
property :id, Serial
property :uuid, UUID
property :title, String
property :text, Text
has n, :comments
end
I want to be able to produce JSON web-service documents that look like this:
{
"href": "http://example.com/articles/1",
"id": "390072fc-c75e-4548-8431-937464a65c7c",
"title": "my-cool-post",
"text": "Loren Ipsum",
"comments_href: "http://example.com/articles/1/comments"
}
{
"href": "http://example.com/articles",
"item_count: 1,
"items": [
{
"href": "http://example.com/articles/1",
"id": "390072fc-c75e-4548-8431-937464a65c7c",
"title": "my-cool-post",
"text": "Loren Ipsum",
"comments_href: "http://example.com/articles/1/comments"
}
]
}
Important things to note about these documents:
- They are highly customized. Obviously, the extensive customization of the attributes used in the JSON prevents me from doing this in the controller, and writing a special #to_json on the model is icky.
- A single
$items[*]
element is identical to the entire document for that object. - The order, while techically insignificant, is extremely important for debugging. Its very useful to be able to always look in the same place in a document for an certain attribute.
- These documents can be huge, containing 100s or 1000s of items. Speed is important.
- The pretty-indenting and spacing of the document in Development mode. Additionally, these documents should be optimized json in production.
Here is how I'd ideally like to write the view templates for these documents:
{
:href => absolute_uri(article),
:id => article.uuid,
:title => article.title,
:text => article.text,
:comments_href => absolute_uri(article.comments)
}
{
:href => absolute_uri(:articles),
:item_count => @articles.size
:items => @articles.map { |article| partial(:article) }
# OR
:items => partial(:article, :with => @articles)
}
Important stuff about this:
- These are written ruby-hash style. Even more awesomeness would be using the
1.9-style:
{href: absolute_uri(:articles), item_count: @articles.size}
- The #partial needs to return an Array, not a string, to that the #to_json at the end works correctly.
- The #partial needs to be able to find the non-underscored template. Its
silly call the first one
_article.json.rj
then haveshow
just be a single line ofpartial(:article)
.- I don't mind calling the first one
article.json.rj
instead, and just having the show action in the controller explicitly render the right template.
- I don't mind calling the first one
-
Because of the desire for fixed ordering and the new-style hash format, it may be desirable to write a custom parser, rather than eval'ing the document as a ruby hash. Yehuda mentioned the Johnson Ruby JS engine might be useful for this, so long as in the template, we don't have to wrap the attribute names in double-quotes.
-
It would be neat if the render method in #show controller actions would automatically look for
#{controller_name.singularize}.template
after looking forshow.template
and not finding it. -
Have a way to add a partial template search path, so that something like this is possible:
{ :id => article.uuid, :author => partial(:person, :with => article.author), ... }
and I could set Articles controller with the additional template search path of
/people
to find the:person
partial