Hi guys,

I think this may be too daunting a task, but I'd like to propose a change 
to the way views are rendered in Rails.

Currently, a template handler converts a template to a string containing 
Ruby code, which then gets evaluated in a context that has certain 
variables present. The code is actually stored as a method on a module as 
far as I can see.

This is all well and good, but I'm interested in using multi-gets to 
efficiently cache the rendering of a collection of objects. Right now I see 
no easy way to do it in PartialRenderer, since the state of the rendering 
is shared between each render. The current code is something like this:

  collection.map do |object|
    locals[as] = object
    template.render(view, locals) # returns a string.
  end

I think the code would be more robust, maintainable, and generally just 
easier to work with if the compiled views were instead classes that looked 
like this:

  class SomeAnonymousCompiledView
    def initialize(context, locals = {})
      @context, @locals = context, locals
    end

    def render
      output_buffer = ""
      output_buffer << "<h1>I was rendered by ERB!</h1>"
      output_buffer << some_local
      output_buffer
    end

    # Template handlers can optionally define a cache_key method. This 
could e.g.
    # encapsulate the stuff currently handled by Cache Digests, but could 
also use
    # the locals.
    def cache_key
      @locals[:fiddle]
    end

    def method_missing(*args)
      # This could be a way to handle local lookups.
    end
  end

The project I'm working on, Curly, is a template handler that has a 
built-in concept of presenters. Say there's a template 
"posts/show.html.curly" containing the following:

  <h1>{{title}}</h1>

It would have a matching presenter in 
"app/presenters/posts/show_presenter.rb":

  class Posts::ShowPresenter < Curly::Presenter
    presents :post  # the controller would assign @post

    def title # the return value is inserted in the template when rendered
      post.title
    end

    # Right now Curly generates code that checks the cache key and uses
    # Action View's existing cache system with the given key. This cannot 
work
    # when rendering a collection, unfortunately.
    def cache_key
      post
    end
  end

I'd love to have my template handler generate the following class:

  class CompiledPostsShowView
    def initialize(context, locals = {})
      @context, @locals = context, locals
    end

    def render
      @rendered ||= "<h1>#{presenter.title}</h1>"
    end

    # This would be used automatically by Rails if defined.
    def cache_key
      presenter.cache_key
    end

    private

    def presenter
      @presenter ||= 
Curly.presenter_for_path(@context.virtual_path).new(@context, @locals)
    end
  end

By wrapping each instance of a rendering in an object, we can encapsulate 
and carry around the state, reusing the cache key in multiple locations.

I'm not sure how easy it would be to retrofit this on top of ERB, but it 
should be possible.

I'd be willing to put in the work, I just want to know if this is something 
Core is interested in.

Cheers,
Daniel (@dasch)

-- 
You received this message because you are subscribed to the Google Groups "Ruby 
on Rails: Core" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/rubyonrails-core?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to