August 4, 2020
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.
{% raw %}
{% if user %}
Hello {{ user.name }}
{% endif %}
{% endraw %}
However sometimes we have a liquid template which is using another liquid template. Here is an example.
{% raw %}
<!DOCTYPE html>
<html>
<head>
<style>{% asset 'main.css' %}</style>
</head>
<body>
{% partial 'header' %}
<h1>Home Page</h1>
</body>
</html>
{% 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.
{% raw %}
* {
color: {{ theme.text_color }};
}
a {
color: {{ theme.link_color }};
}
{% endraw %}
{% raw %}
<nav>
{{ organization.name }}
</nav>
{% 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.
# app/lib/liquid/tags/asset.rb
module Liquid
module Tags
class Asset < Liquid::Tag
def initialize(tag_name, name, tokens)
super
@name = name.strip.remove("'")
end
def render(context)
new_context = context.environments.first
asset = Template.asset.find_by(filename: @name)
Liquid::Template.parse(asset.content).render(new_context).html_safe
end
end
end
end
Let's create a tag that will handle partials.
# app/lib/liquid/tags/partial.rb
module Liquid
module Tags
class Partial < Liquid::Tag
def initialize(tag_name, name, tokens)
super
@name = name.strip.remove("'")
end
def render(context)
new_context = context.environments.first
# Remember here we are not passing extension
asset = Template.partial.find_by(filename: @name + ".liquid")
Liquid::Template.parse(asset.content).render(new_context).html_safe
end
end
end
end
Let's create a new initializer and we need to register these tags in that initializer.
# config/initializers/liquid.rb
require 'liquid/tags/asset'
require 'liquid/tags/partial'
Liquid::Template.register_tag('asset', Liquid::Tags::Asset)
Liquid::Template.register_tag('partial', Liquid::Tags::Partial)
Restart the server and now we can render the home.liquid template
like this.
template = Template.template.find_by(filename: "home.liquid")
attributes = {
organization: {
name: "Example"
},
theme: {
text_color: "#000000",
link_color: "#DBDBDB"
}
}
Liquid::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.
Follow @bigbinary on X. Check out our full blog archive.