Last active
December 20, 2015 22:28
-
-
Save stex/6204845 to your computer and use it in GitHub Desktop.
Liquid Rendering Helper for Rails controllers and views. Simply include LiquidHelpers::Rendering in each controller you want liquid rendering to be available. The main method you'll have to change to get this working in your application is `get_template_content` which fetches the actual template content either from disk or database.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#This module contains all necessary methods to render liquid templates | |
#in a controller. | |
module LiquidHelpers | |
module Rendering | |
def self.included(base) | |
base.class_eval do | |
helper_method :render_liquid if respond_to?(:helper_method) | |
end | |
end | |
protected #Make these actions only available in controllers and views | |
# Renders a liquid template | |
# Parameters: | |
# - Path to a skin template or an already loaded template content (not yet parsed) | |
# - [optional] Layout for the template to be rendered in | |
# - [optional] Options-Hash | |
# Options may include: | |
# +:assigns+:: Assigns to be available to the rendered template | |
# | |
# +:layout+:: If the layout was not given as the second parameter | |
# it may be handed in through the options | |
# | |
# +:return_string+:: If set to true, the function will return the rendered content | |
# instead of sending it to the user's browser directly | |
# | |
# +:pre_rendered+:: If this is set to +true+, the template (first argument) will | |
# not be rendered through liquid any more and just be passed | |
# to the layout rendering (if any) | |
# | |
# +:content_given+:: If set to true, the first argument will be interpreted as an already | |
# loaded liquid template content and be passed to the rendering function | |
# | |
# +:partial+:: If set to true, a partial will be rendered. | |
# Only works if no layout was given. | |
#-------------------------------------------------------------- | |
def render_liquid(*args) | |
template_path_or_content = args.first | |
layout_path = nil | |
assigns = nil | |
options = {} | |
if args.second.is_a?(Hash) | |
options = args.second | |
else | |
layout_path = args.second | |
options = args.third if args.third | |
end | |
layout_path ||= options[:layout] | |
pre_rendered_template = options[:pre_rendered]; pre_rendered_template = false if pre_rendered_template.nil? | |
return_string = options[:return_string]; return_string = false if return_string.nil? | |
rendering_options = {} | |
rendering_options[:content_given] = options[:content_given] | |
rendering_options[:partial] = options[:partial] | |
#Build the correct assigns hash | |
assigns ||= options[:assigns] || {} | |
assigns.stringify_keys! | |
#Run .to_liquid on assigns. This should usually not be necessary, but | |
# for some reason liquid fails to run it itself, especially for arrays. | |
assigns.each do |key, val| | |
if val.is_a?(Array) | |
assigns[key] = val.map(&:to_liquid) | |
end | |
end | |
#If the template is already rendered, just push it to the layout rendering (if any) | |
if pre_rendered_template | |
rendered_content = template_path_or_content | |
rendered_content = render_layout(template_path_or_content, layout_path, assigns) if layout_path | |
else | |
#Otherwise, render the template in the optional layout | |
rendered_content = layout_path ? render_template_in_layout(template_path_or_content, layout_path, assigns, rendering_options) : render_template(template_path_or_content, assigns, rendering_options) | |
end | |
return_string ? rendered_content : render(:text => rendered_content) | |
end | |
private | |
# Renders a template in the given layout | |
# TODO: Check, if we have to grab the {% assigns %} from the rendered template and push them to the layout. | |
#-------------------------------------------------------------- | |
def render_template_in_layout(template, layout, assigns = {}, options = {}) | |
rendered_template = render_template(template, assigns, options) | |
render_layout(rendered_template, layout, assigns) | |
end | |
# Renders a given template, returns the rendered content | |
#-------------------------------------------------------------- | |
def render_template(template, assigns = {}, options = {}) | |
set_virtual_file_system(template) | |
parsed_template = Liquid::Template.parse(get_template_content(template, options)) | |
parsed_template.render(assigns, :registers => default_registers) | |
end | |
# Renders a layout file | |
#-------------------------------------------------------------- | |
def render_layout(rendered_template, layout, assigns = {}) | |
render_template(layout, assigns.merge({'yield' => rendered_template})) | |
end | |
# Sets liquid up to use the virtual filesystem for templates | |
#-------------------------------------------------------------- | |
def set_virtual_file_system(path) | |
::Liquid::Template.file_system = LiquidHelpers::VirtualFileSystem.new(path, (user_session.skin rescue nil)) | |
end | |
# Returns the template content for a given template path | |
#-------------------------------------------------------------- | |
def get_template_content(path_or_content, options = {}) | |
if options[:content_given] | |
return path_or_content | |
end | |
begin | |
user_session.skin.template_content(path_or_content, options) || raise(VirtualFileSystem::FileSystemError, path_or_content) | |
rescue | |
"<strong>The template '#{path_or_content}' could not be loaded correctly.</strong>" | |
end | |
end | |
def default_registers | |
registers = {} | |
registers[:controller] = self if self.class < ActionController::Base | |
registers | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This class is a replacement for the normal liquid file system | |
# which loads files from disk. | |
# This FileSystem gets its content from either cache or database. | |
module LiquidHelpers | |
class VirtualFileSystem | |
class FileSystemError < StandardError | |
end | |
attr_reader :root, :skin | |
def initialize(root, skin) | |
@root = root | |
@skin = skin | |
end | |
# Renders a liquid partial | |
#-------------------------------------------------------------- | |
def read_template_file(template_path) | |
get_template_content(template_path) | |
end | |
private | |
# Returns the template content for a given template path | |
# Also validates the path | |
#-------------------------------------------------------------- | |
def get_template_content(path) | |
raise FileSystemError, "Illegal template name '#{path}'" unless path =~ /^[^.\/][a-zA-Z0-9_\/]+$/ | |
content = skin.template_content(path, :partial => true) | |
unless content | |
raise FileSystemError, "Include not found: '#{path}'" | |
end | |
content | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment