Liquid is a flexible and safe template engine that allows you to write code inside the actual template. It was extracted from Shopify and is pretty awesome if you need your templates be editable by non-programmers. This is a most important part, as such users might break the whole application. In this case Liquid is perfect. Also, its kind of similar to Blitz template engine, which i was using on PHP.
The documentation is not the perfect, but enough to understand the concepts, so i’ll just jump straight to the matter.
Subject
Lets assume that all our templates are stored in database and we dont store anything in filesystem. And we need to use small parts as snippets to embed into actual template.
Implementation
The model where we store all snippets with be named Snippet. Fields:
- ID – Primary key
- Name – Actual name of the snippet used in tempates
- Body – Content of the snippet
- Created/Updated timestamps – DateTime stamps for internal use
And the active record model:
class Snippet < ActiveRecord::Base NAME_FORMAT = /^[a-z\d\_\-]{2,64}$/i # Define your own name format validates_presence_of :name, :body validates_length_of :name, :within => 2..64 validates_format_of :name, :with => NAME_FORMAT validates_uniqueness_of :name, :case_sensitive => false end
Now, lets define the custom liquid tag “snippet”:
class SnippetTag < Liquid::Tag def initialize(tag_name, snippet_name, tokens) super @name = snippet_name end def render(context) # You might want to define caching mechanism here snippet = Snippet.find_by_name(@name) unless snippet.nil? Liquid::Template.parse(snippet.body).render else "Error: Snippet #{@name} was not found!" end end end
Now, register the tag:
Liquid::Template.register_tag('snippet', SnippetTag)
And use it within your template:
This is a custom tag that renders a widget: {% snippet sample_snippet %}
If the requested snippet was not found or does not exists renderer will replace the tag with error message, which might be adjusted for your personal needs or hidden. Also, you can use nested snippets, but in this case you have to think about right snippet template caching approach.
Using Liquid drops
A drop in liquid is a class which allows you to use predefined data collection methods in the template. If you would like to make data available to the web designers which you don’t want loaded unless needed then a drop is a great way to do that.
Lets make a drop for a basic dataset for Post model (blog posts for example):
class PostsDrop < Liquid::Drop # fetch all posts def all Post.all end # fetch N most popular posts def popular(num=10) Post.all(:order => 'pageviews DESC', :limit => num) end end
Define a template for this collection:
Popular posts:
{% for post in posts.popular %} Post: {{ post.title }} {% endfor %}
Load a drop into the template:
template = Liquid::Template.parse(YOUR_TEMPLATE).render('posts' => PostsDrop.new)
With such scheme you can hook up custom snippet that renders a list of objects from your drop.
Pretty cool. Works on Rails 3.
