Shopify's Liquid Templates is a great way for templating in Ruby on Rails applications.
If the template is as simple as this one then there are no issues.
1{% raw %} 2{% if user %} 3 Hello {{ user.name }} 4{% endif %} 5{% endraw %}
However sometimes we have a liquid template which is using another liquid template. Here is an example.
home.liquid
1{% raw %} 2<!DOCTYPE html> 3<html> 4 <head> 5 <style>{% asset 'main.css' %}</style> 6 </head> 7 <body> 8 {% partial 'header' %} 9 <h1>Home Page</h1> 10 </body> 11</html> 12{% endraw %}
In the above case home.liquid is using two other liquid templates main.css and header.liquid.
Let' see what these templates look like.
main.css
1{% raw %} 2* { 3 color: ; 4} 5a { 6 color: ; 7} 8{% endraw %}
header.liquid
1{% raw %} 2<nav> 3 4</nav> 5{% endraw %}
In order to include the assets and the partials we need to create liquid tags.
Let's create a tag which will handle assets.
1 2# app/lib/liquid/tags/asset.rb 3 4module Liquid 5module Tags 6class Asset < Liquid::Tag 7def initialize(tag_name, name, tokens) 8super 9@name = name.strip.remove("'") 10end 11 12 def render(context) 13 new_context = context.environments.first 14 asset = Template.asset.find_by(filename: @name) 15 16 Liquid::Template.parse(asset.content).render(new_context).html_safe 17 end 18 end 19 20end 21end
Let's create a tag that will handle partials.
1 2# app/lib/liquid/tags/partial.rb 3 4module Liquid 5module Tags 6class Partial < Liquid::Tag 7def initialize(tag_name, name, tokens) 8super 9@name = name.strip.remove("'") 10end 11 12 def render(context) 13 new_context = context.environments.first 14 15 # Remember here we are not passing extension 16 asset = Template.partial.find_by(filename: @name + ".liquid") 17 18 Liquid::Template.parse(asset.content).render(new_context).html_safe 19 end 20 end 21 22end 23end
Let's create a new initializer and we need to register these tags in that initializer.
1 2# config/initializers/liquid.rb 3 4require 'liquid/tags/asset' 5require 'liquid/tags/partial' 6 7Liquid::Template.register_tag('asset', Liquid::Tags::Asset) 8Liquid::Template.register_tag('partial', Liquid::Tags::Partial)
Restart the server and now we can render the home.liquid template like this.
1template = Template.template.find_by(filename: "home.liquid") 2 3attributes = { 4organization: { 5name: "Example" 6}, 7theme: { 8text_color: "#000000", 9link_color: "#DBDBDB" 10} 11} 12 13Liquid::Template.parse(template.content).render(attributes).html_safe
Here we have a simple implementation of the tags. We can do much more, if needed, like looping over items to parse each item from the partial. That can be done by registering a separate tag for the item and passing in the id of the item so that the specific item can be found and parsed.