Skip to content

Layout Tag Implementation #37

@RtypeStudios

Description

@RtypeStudios

Hi Chamnap,

Thank you for making this library. I have been working with the code and have a working prototype for implementing the layout tag similar to what shopify has: https://help.shopify.com/en/themes/liquid/tags/theme-tags#layout (I doubt my implementation is the same)

My method was this:

  1. Created a simple layout tag:
class Liquid::Tags::LayoutTag < Liquid::Tag

  def initialize(tag_name, markup, tokens)
    super
    @template = markup.delete("\"").strip
  end

  def render(context)
    context.environments.first["layout_override_filename"] = @template
    ""
  end

end
  1. Then extended the view class:
  class TemplateHandler

      def self.call(template)
        "Liquid::Handlers::TemplateHandler.new(self).render(#{template.source.inspect}, local_assigns)"
      end

      def initialize(view)
        @view       = view
        @controller = @view.controller
        @helper     = ActionController::Base.helpers
      end

      def render(template, local_assigns={})

        assigns = if @controller.respond_to?(:liquid_assigns, true)
          @controller.send(:liquid_assigns)
        else
          @view.assigns
        end

        # check if there is a layout override
        layout_override_filename = assigns["layout_override_filename"]

        # if we are processing the layout and there is an override, replace the template with the override content.
        if @view.content_for?(:layout) && !layout_override_filename.nil?
          Rails.logger.info "Rendering layout override from #{layout_override_filename}"
          template = read_template_from_file_system(registers, layout_override_filename)
        end

        assigns['content_for_layout'] = @view.content_for(:layout) if @view.content_for?(:layout)
        assigns.merge!(local_assigns.stringify_keys)

        liquid      = Liquid::Template.parse(template)
        liquid.send(render_method, assigns, filters: filters, registers: registers).html_safe
      end

      def filters
        if @controller.respond_to?(:liquid_filters, true)
          @controller.send(:liquid_filters)
        else
          [@controller._helpers]
        end
      end

      def registers
        {
          view: @view,
          controller: @controller,
          helper: @helper,
          file_system: Liquid::Handlers::FileSystem.new(@view)
        }
      end

      def compilable?
        false
      end

      def render_method
        (::Rails.env.development? || ::Rails.env.test?) ? :render! : :render
      end

      def read_template_from_file_system(registers, name)
        file_system = registers[:file_system] || Liquid::Template.file_system
        file_system.read_template_file(name)
      end

    end

The template handler then replaces the view with the select template when rendering occurs. This was really just a proof of concept. If I clean this up and submit it as a pull request would that be useful to you or others do you think?

Any suggestions on improvements? Liquid is very new to me and I had troubles finding a good way to pass the template override through and ended up using the environment.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions