JSON Templating

Hello there,

As a bit of background, I'm in the early design phases of a large RoR
project for the company I work for and we're planning on sticking with
Rails for the next 5-10 years. We're at this point in the project
we're trying to get some good practices and customize the framework to
work for what we're going to be needing need. We've considered the
pros/cons of going with a full blown web-app (Backbone.js style) vs. a
static limited JS based Rails app. While we would have loved to go
with a webapp, I've determined that going with Backbone.js would
cause:

- Complete duplication of views and routes (a maintenance issue in the
long run)
- Difficulty tracking polymorphic associations and their routes
- Wouldn't allow us to use the view helpers on the client side
(maintenance issue)
- Duplication of some of the model information
- Slow client-end computers (beyond our control), which would have
difficulty running it

To try and reduce this, we're decided to go with a more hybrid
approach but to push more of the logic back to the server side while
still maintaining a RESTFUL architecture as an API as best as
possible. We're planning on having the initial page loads done
normally using Rails, and then any manipulations on the page send the
request via AJAX and receiving back a JSON object which contains the
rendered partial, and some additional information (ie. flash updates,
JSON representation of the object, additional JS includes if
necessary, etc.)

The problem we're running into, is that from my understanding, we
cannot maintain the RESTFUL architecture and have multiple partials/
views for that same data. As an example of this, if I wanted to
request a list of Orders from the server via orders/index, it would
return only one view of the data. If I had an extended table, a list,
or some other view/partial/widget which I wanted the requested partial
to be used for.

To that end, I've added a params[:partial] (which is either an add-on
on the route, or a url parameter) that provides the server both with
the information that is being requested, as well as the view which I
am expecting it to come in. This would work well on it's own, however
I'd also like to have any additional information sent down from the
server at the same time (ie. flash updates, JSON representation of the
data, etc.). Ideally we want this to be flexible, fast, and sent down
from the server in JSON format.

To that end, I've overriden the existing JSON responder as follows,
and you may notice the hack I've had to use to have it render the HAML/
ERB templates inside of the JSON:

module ExtraFunctions
  def partial_options
    params.include?(:partial) ? { :partial => params[:partial] } : {}
  end

  def flash_options
    { :file => 'layouts/_flash.html.haml' }
  end
end

ApplicationController.send :include, ExtraFunctions

#I would love to be using the ERB templating and views
#instead of this kludge. But this will have to do.

ActionController::Renderers.add :json do |json, options|

  #Change the format so we can render the html templates
  self.formats = [:html]
  options = { :layout => false }

  partial_opt = options.merge(self.respond_to?(:partial_options) ?
self.partial_options : {})
  flash_opt = options.merge(self.respond_to?(:flash_options) ?
self.flash_options : {})

  obj = {
    json: json.as_json,
    partial: render_to_string(partial_opt),
    flash: flash,
    flash_partial: render_to_string(flash_opt),
    user: @current_user
    #js-includes: #Working on this
  }

  #Change the format back
  self.formats = [:json]

  json = obj.to_json(options) unless obj.kind_of?(String)
  json = "#{options[:callback]}(#{json})" unless
options[:callback].blank?

  self.content_type ||= Mime::JSON
  json
end

You'll notice there is a spot in there for js-includes, the reason for
that is that I want the ability to have dynamic includes late in the
game using head.js. This would be for easier dependency management,
as the initial view would not be including some of the partials that
are requested via AJAX (ie. if I grabbed a form to enter a new
address, and that form has some AJAX checking on it as included in the
top of it using a content_for tag). Ideally, what I'd really like
this to be is a JSON layout to look something like (though with a more
sugar coated syntax I would hope):

** json/application.json.erb **
{
    json: <%= json.as_json %>,
    partial: <%= render_to_string(partial_opt) %>,
    flash: <%= flash %>,
    flash_partial: <%= render_to_string(flash_opt) %>,
    user: <%= @current_user =>,
    js-includes: <%= yield :js_includes %>,
    <%= yield =>
}

I've been working on these considerations/issues for a while, and my
questions are two:

1) Is there anything blatantly screamingly stupid about what we're
doing? Is there a better or more standard solution?

2) Is there a way to have ERB render the templates for JSON?

- Adam