BigBinary Blog

We write about Ruby on Rails, React.js, React Native, remote work, open source, engineering and design.

Render a liquid template when the template is a liquid template

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.

Sandip Mane in Rails
04, 2020
Share

You might also like

Rails 6.1 adds support for PostgreSQL interval data type

Rails 6.1 allows per environment configuration support for Active Storage

Rails 6.1 adds support for belongs_to to has_many inversing

Rails 6.1 adds strict_loading to warn lazy loading associations

Rails 6.1 adds where.associated to check association presence

Subscribe to our newsletter