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.

{% if user %}
  Hello {{ user.name }}
{% endif %}

However sometimes we have a liquid template which is using another liquid template. Here is an example.

home.liquid
<!DOCTYPE html>
<html>
  <head>
    <style>{% asset 'main.css' %}</style>
  </head>
  <body>
    {% partial 'header' %}
    <h1>Home Page</h1>
  </body>
</html>

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
* {
  color: {{ theme.text_color }};
}
a {
  color: {{ theme.link_color }};
}
header.liquid
<nav>
{{ organization.name }}
</nav>

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.