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.