Chaining Rails Template (view) Handlers

I have been looking for a way to get rid of all the ERB markup in the file and simply use plain HTML, albeit with my custom set of HTML tags. I don’t want to learn a new markup language just to do something simple but on the same token don’t want <%= … do %> … <% end %> splattered all over the page either. For example, I want to use “<row>…</row>” to invoke/substitute <%= row do %>…<% end %> automatically when the page is processed.

Rails 3 makes it easy to chain preprocessors to assets that will perform manipulations on the file prior to storing it, as the guides talk about here. However, this method limits you to only the assests files – scripts, css, images, for the most part.

I’ve been searching for a way to chain template handlers to action views in the same manner. For example, if you have a file called index.html.erb.something the framework would first process the Something handler, followed by the ERB handler. So far I’ve not been able to find a way to handle it quite in this form, however I have found a way to inject your preprocessing without changing extensions at all.

To do this I created the following initializer, with a simple but functional example:


module CustomMarkupHandler
MAPPINGS = {
`Chaining` =&gt; `Awesome`
}
def self.call(template)
begin
details = {
:locals =&gt; template.locals,
:virtual_path =&gt; template.virtual_path,
:updated_at =&gt; template.updated_at
}
updated_source = template.source
MAPPINGS.each_pair {|find, replace|
updated_source = updated_source.gsub(find, replace)
}
new_template = ActionView::Template.new(updated_source, template.identifier, template.handler, details)
rescue
new_template = template
end
ActionView::Template::Handlers::ERB.call(new_template)
end
end
# Custom Markup Language registration
ActionView::Template.register_template_handler :erb, CustomMarkupHandler
end

Note that if you copy and paste this code you’ll need to replace the backwards quote with a normal one – my syntax highlighter doesn’t like single or double quotes.

Let’s walk through what this is doing:

  1. It defines a custom markup handler module
    • Typically you’d want to look up the registered handler for a given extension, however since we are overriding the handler for ERB, we’ve hard coded it here to use ActionView::Template::Handlers::ERB.
    • The code here simply does a gsub BEFORE allowing ERB to process the source. Create any *.erb page with the word “Chaining” in it and it will be replaced at render time with “Awesome”.
      • Want a guru to validate this part – I believe that by adding this before the ERB process it should not interfere with the way that the file is cached and served back up later, thus retaining roughly the same performance that we had prior to this injection.
    • The source attribute of the ActionView::Template is read only so we copied out the attributes we needed (details, identifier, handler) and simply use them, along with our updated source, to create a new template.
    • We then can send our modified source template through the ERB handler for traditional markup. Since we ran our modifications before ERB we can easily gsub in method calls that will be handled as if they were in the file natively.
    • Finally, just in case something unexpected happens, the whole thing is wrapped in begin/rescue that will simply process the unadulterated template, hopefully preventing a 500 error.
  2. It registers the handler as the default handler for *.erb files
    • This means that ALL files ending in *.erb will be routed through this new handler instead.

About the author

Jason McDonald

View all posts

Leave a Reply

Your email address will not be published. Required fields are marked *

Time limit is exhausted. Please reload CAPTCHA.