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.
If this blog was helpful, check out our full blog archive.