Render a liquid template when the template is a liquid template

Sandip Mane

Sandip Mane

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.

home.liquid
{% 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.

main.css
{% raw %}
* {
  color: {{ theme.text_color }};
}
a {
  color: {{ theme.link_color }};
}
{% endraw %}
header.liquid
{% 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.

Stay up to date with our blogs.

Subscribe to receive email notifications for new blog posts.