Skip to content

Instantly share code, notes, and snippets.

@peter
Last active December 1, 2016 09:15
Show Gist options
  • Save peter/e05ed4d45c34174d17d795329db488f9 to your computer and use it in GitHub Desktop.
Save peter/e05ed4d45c34174d17d795329db488f9 to your computer and use it in GitHub Desktop.
Using handlebars.rb (handlebars.js) from Rails 4
################################################################
# config/initializers/handlebars.rb:
################################################################
template_path = File.join(Rails.root.to_s, 'app/views')
helpers = {
t: lambda do |context, key|
I18n.t(key)
end,
path: lambda do |context, path_name|
Seashore::Gangway::LocalUrlHelper.localized_path_for(path_name)
end,
css_classes: lambda do |context|
# NOTE: arrays in context are V8:Array instances, see: https://github.com/cowboyd/therubyracer/wiki/Accessing-V8-Objects-From-Ruby
css_classes = context['css_classes'].try(:to_a)
hide_from_classes = context['hide_from'].try(:to_a).try(:map) { |user_type| "hide-from-#{user_type}" }
[css_classes, hide_from_classes].compact.flatten.join(" ")
end,
join: lambda do |context, vals, sep|
vals && vals.join(sep || " ")
end,
ifEq: lambda do |context, val1, val2, block|
if val1 == val2
block.fn(context)
else
block.inverse(context)
end
end
}
options = {
cache: !Rails.env.development?,
template_path: template_path,
partials_path: File.join(template_path, 'partials'),
helpers: helpers
}
Rails.configuration.handlebars_context = HandlebarsContext.new(options)
################################################################
# app/models/handlebars_context.rb:
################################################################
require 'handlebars'
class HandlebarsContext
PREFIX = '_'
EXT = '.hbs'
attr_reader :handlebars, :cached_templates, :cached_partials, :options
def initialize(options = {})
options.assert_valid_keys(:cache, :template_path, :partials_path, :helpers)
default_options = {template_path: '.', partials_path: './partials', helpers: {}}
@options = default_options.merge(options)
@cached_templates = {}
@cached_partials = {}
@handlebars = Handlebars::Context.new
@handlebars.partial_missing do |name|
lambda do |this, context, options|
path = partial_path(name)
if partial = lookup_partial(path)
render_compiled(partial, context)
else
puts "[ERROR] HandlebarsContext could not find partial #{name} at path #{path}"
end
end
end
@options[:helpers].each do |name, block|
@handlebars.register_helper(name, &block)
end
end
def render(path, data)
template = lookup_template(template_path(path))
if template
render_compiled(template, data)
else
puts "[ERROR] HandlebarsContext#render could not find template at path #{path}"
end
end
def lookup_template(path)
return @cached_templates[path] if @cached_templates[path] && options[:cache]
if File.exists?(path)
template_str = IO.read(path)
@cached_templates[path] = handlebars.compile(template_str)
else
nil
end
end
def lookup_partial(path)
return @cached_partials[path] if @cached_partials[path] && options[:cache]
if File.exists?(path)
template_str = IO.read(path)
@cached_partials[path] = handlebars.compile(template_str)
else
nil
end
end
private
def render_compiled(template, data)
template ? template.call(data) : nil
rescue Exception => e
puts "[ERROR] HandlebarsContext#render exception: #{e.message} #{e.backtrace.join("\n")}"
""
end
def template_path(path)
filename = PREFIX + File.basename(path) + EXT
File.join(options[:template_path], File.dirname(path), filename)
end
def partial_path(name)
filename = PREFIX + name + EXT
File.join(options[:partials_path], filename)
end
end
################################################################
# application_helper.rb:
################################################################
def render_hbs(path, data)
Rails.configuration.handlebars_context.render(path, data).try(:html_safe)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment