Skip to content

Instantly share code, notes, and snippets.

@alexsanford
Created August 29, 2012 01:32
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save alexsanford/3505912 to your computer and use it in GitHub Desktop.
Save alexsanford/3505912 to your computer and use it in GitHub Desktop.
Render rails views inside a liquid block in Locomotive CMS
<!-- File: app/views/layouts/application.html.erb -->
<!DOCTYPE html>
<html>
<head>
<title>Locomotive Test</title>
<%= stylesheet_link_tag "application", :media => "all" %>
<%= javascript_include_tag "application" %>
<%= csrf_meta_tags %>
</head>
<body>
<!-- The :path option here can specify the path to any page in the CMS -->
<%= locomotive_layout(:path => '/rails-layout', :block => 'content') do %>
<%= yield %>
<% end %>
</body>
</html>
# File: config/initializers/inherited_block.rb
require 'locomotive/liquid/tags/inherited_block'
class InheritedBlock < ::Locomotive::Liquid::Tags::InheritedBlock
def render(context)
rails_view = context.registers[:rails_view]
if rails_view.present? && name == context.registers[:rails_view_block]
rails_view
else
super
end
end
::Liquid::Template.register_tag('block', InheritedBlock)
end
# File: app/helpers/rails_view_helper.rb
require 'locomotive'
module RailsViewHelper
def locomotive_layout(options = {}, &block)
options = {
:path => '',
:block => 'content',
}.merge(options)
output = capture &block
page = locomotive_page(options[:path])
template = page.try(:template)
if template.present?
options = options_for_current_controller if options.blank?
context = current_context(page, output, options)
template.render(context).html_safe
else
output
end
end
protected
include Locomotive::Routing::SiteDispatcher
def options_for_current_controller
options = {}
options[:title] = @page_title || I18n.t("#{params[:controller]}.#{params[:action]}", :scope => :page_titles, :default => '').presence || I18n.t(params[:controller], :scope => :page_titles)
options[:full_path] = request.path.slice(1..request.path.length - 1)
options[:slug] = options[:full_path].try(:parameterize, '_')
options
end
def normalize_path(path)
norm = path
norm.sub!(/^\/+/, '')
norm.sub!(/\/+$/, '')
norm.gsub!(/\/{2,}/, '/')
if norm.empty?
'index'
else
norm
end
end
def locomotive_page(fullpath)
fullpath = normalize_path(fullpath)
current_site.pages.where(:fullpath => fullpath).first
end
# Sets up the context to be passed in for rendering
# Any extra parameters passed in here must also
# be mixedin to the locomotive rendering controller
def current_context(page, content, options={})
[:title, :slug, :fullpath].each do |option|
page.send(:"#{option}=", options[option]) if options[option].present?
end
assigns = {
'site' => current_site,
'page' => page,
'contents' => Locomotive::Liquid::Drops::ContentTypes.new,
'current_page' => self.params[:page],
}
registers = {
:controller => self,
:site => current_site,
:page => page,
:inline_editor => false,
:rails_view => content,
:rails_view_block => options[:block],
}
::Liquid::Context.new({}, assigns, registers)
end
end
@bindzus
Copy link

bindzus commented Feb 27, 2013

This was extremely useful and one of the only sources I could find explaining how to use Locomotive templates from Rails, thank you!

I needed to be able to fill multiple blogs, so I forked your solution and made some modifications, I'm new to Rails, so maybe I made some bad choices, comments are welcome :-)

https://gist.github.com/bindzus/5032895

@nmccready
Copy link

Is there anyway to do the opposite and override the basic template with a rails layout? IE I want it to use my Header and footer which are under SCC.

@siklodi-mariusz
Copy link

I need some help with this. I want to keep the header and the footer from Locomotive and place content rendered by rails in between. I used the example from above and it seems to work, the page gets rendered with the header and footer but there is a problem with the images that I have in the header.

Instead of the images I get this error: Liquid error: undefined method `[]' for nil:NilClass.

in application.html.erb i have this:

<%= locomotive_layout(:path => '/rails-layout', :block => 'main') do %>
  <%= yield %>
<% end %>

In Locomotive I have a page rails-layout that looks like this:


---
title: Rails-layout

# true if the page is included in the menu
listed: false
# true if the page is published
published: false


---
{% include header %}

    {% block main %}{% endblock %}

{% include footer %}

and in a view in rails i have this:

<div id="map" style='width: 100%; height: 800px;'></div>
<script>
  $(document).ready(function() {
    var handler = Gmaps.build('Google');
    handler.buildMap({ provider: {}, internal: {id: 'map'}}, function(){
      var markers = handler.addMarkers(<%=raw @hash.to_json %>);
      handler.bounds.extendWith(markers);
      handler.fitMapToBounds();
    });
  });
</script>

Everything is rendered as it should except the images.

I don't know how to solve this. I'm a beginner at coding and some help would be greatly appreciated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment