I am working on a new application that will use some Liquid templates to allow our clients to edit some templates.

We will store these templates in the Database, load them, parse them and render them. So far, no magic.

But, I needed to have some "partials" for these. I wanted some common elements (like image galleries) to be available for the client to use in that specific template.

The way you normally accomplish this is by using an include tag, but I needed a little bit more control. Not all the clients will have the same partials and I also wanted the clients to be able to edit these partials.

So after reading the Liquid source code, I found a really easy way to do this.

You just need an object that responds to read_template_file and it can take 1 or 2 arguments (please, go for 2). This method must return the Liquid source of the partial (not a parsed template).

So, here's a really simple one that will work:

# https://gist.github.com/nhocki/3645632

# Class to be used as a Liquid File System for the `include` tag
class LiquidTemplateSystem
  attr_reader :user

  def initialize(user)
    @user = user
  end

  # Return a valid liquid template string
  def read_template_file(template_path, context)
    user.partials.find_by_name(template_path).liquid_source
  end
end


# In the view:
# This `template` has an {% include %} tag.
<%= template.render(obj, registers: {file_system: LiquidTemplateSystem.new(user)}) %>

Default FileSystem

You could also set the default FileSystem with Liquid::Template.file_system = MyNewFileSystem.new. This may be useful if you want the partials to be shared on the database but not different for every user.

Any other way?

Even though I find this to be really easy, another way may exist. If you know of a better way to do this, please let me know.