在HAML文件中使用独立于Rails的布局

Ste*_*ven 36 ruby haml

我的最终目标是创建几个静态HTML文件,以便传递给其他人.

但对于我的工作流程,我希望将HAML作为基本源文件.在这样做的时候,我希望至少在我这边干预这个过程.

现在我有很多页面最终将共享一个共同的布局,我想知道如何合并布局.

这是我目前的代码:

./compile.rb

#!/usr/bin/env ruby

require 'rubygems'
require 'rake'
require 'haml'

FileList.new('./src/*.html.haml').each do |filename|
  if filename =~ /([^\/]+)\.haml$/
    File.open($1, 'w') do |f|
      f.write Haml::Engine.new(File.read(filename)).render
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

./src/layout.html.haml

!!!
%html
  %head
    %title Yay
  %body
    = yield
Run Code Online (Sandbox Code Playgroud)

./src/home.html.haml

= render :layout => 'header' do
  %p This is awesome
Run Code Online (Sandbox Code Playgroud)

现在,这显然不工作,因为渲染方法是未定义出的Rails的背景下,但我希望它得到跨我想要做的地步.

有什么建议?

mat*_*att 75

你混合了两个不同的Rails功能:部分(使用render)布局(使用yield).

您可以将它们中的任何一个(或两个)的类似轨道的版本添加到仅Haml程序中.

谐音

在rails视图中,您可以使用render :partial_name导致文件_partial_name.html.haml在包含视图中的那一点呈现(实际上Rails允许您使用任何支持的模板语言,它会找到正确的文件扩展名以供使用,但我会坚持哈姆在这里).Rails之外render没有,但可以相当容易地添加.

一个简单的render方法只是找到合适的haml文件,渲染它,并返回html字符串以包含在父文件中:

def render(partial)
  # assuming we want to keep the rails practice of prefixing file names
  # of partials with "_"
  Haml::Engine.new(File.read("_#{partial}.html.haml")).render
end
Run Code Online (Sandbox Code Playgroud)

第一个参数Haml::Engine.render是一个范围对象,我们可以使用它来添加haml模板中可用的方法.它默认为Object.new.在简单的情况就是这样,不过,我们可以定义render在顶层方法,它会在Haml的模板的范围是可用的.我们只是render在调用之前将我们的方法放在脚本中Haml::Engine.new(...).render,并在我们的模板中调用它:

!!!
%html
  %head
    %title Hello
  %body
    =render :the_partial
Run Code Online (Sandbox Code Playgroud)

现在,文件_the_partial.html.haml将在输出的适当位置呈现.

局部变量

我们可以更进一步.Rails允许您将局部变量的散列传递给局部变量.Haml还将接受作为局部变量传递的变量散列,作为Haml render方法的第二个参数.因此,如果我们将render方法展开为:

def render(partial, locals = {})
  Haml::Engine.new(File.read("_#{partial}.html.haml")).render(Object.new, locals)
end
Run Code Online (Sandbox Code Playgroud)

我们可以使用看起来像这样的部分:

%p You passed in #{foo}
Run Code Online (Sandbox Code Playgroud)

并从我们的模板中调用它:

%body
  =render :partial, :foo => "bar"
Run Code Online (Sandbox Code Playgroud)

这将呈现

<body>
  <p>You passed in bar</p>
</body>
Run Code Online (Sandbox Code Playgroud)

布局

在Rails中,您可以为视图指定布局,以便所有页面可以共享相同的标题,菜单区域等.这可以通过指定布局文件来完成,您yield可以在其中调用以呈现相关的实际视图.添加到haml的布局稍微有些棘手,但仍然可以完成.

Hamls render方法也接受一个块,因此一个简单的解决方案是渲染布局文件,并传递一个呈现视图文件的块:

Haml::Engine.new(File.read("layout.html.haml")).render do
  Haml::Engine.new(File.read("view.html.haml")).render
end
Run Code Online (Sandbox Code Playgroud)

这将为layout.html.haml渲染的内容view.html.haml提供包含布局文件的渲染内容=yield.

content_for

Rails比这更灵活.它允许您yield在布局文件中多次调用,在每种情况下命名特定区域,并使用content_for视图中的方法指定要在每个区域添加的内容.所以在你的布局文件中:

!!!
%html
  %head
    = yield :title
  %body
    =yield
Run Code Online (Sandbox Code Playgroud)

在你看来:

-content_for :title do
  %title Hello
%p
  Here's a paragraph.
Run Code Online (Sandbox Code Playgroud)

Rails实际工作的方式是首先渲染视图部分,存储所有不同的部分,然后渲染布局,传递一个块,该块yield在布局中调用时提供适当的块.我们可以使用一个小助手类来复制它,以提供content_for方法并跟踪每个区域的渲染块:

class Regions  
  def initialize
    @regions_hash={}
  end

  def content_for(region, &blk)  
    @regions_hash[region] = capture_haml(&blk)
  end

  def [](region)
    @regions_hash[region]
  end
end
Run Code Online (Sandbox Code Playgroud)

这里我们使用该capture_haml方法来获取渲染的haml而不直接输出.请注意,这不会捕获视图的未命名部分.

我们现在可以使用我们的辅助类来渲染最终输出.

regions = Regions.new
unnamed = Haml::Engine.new(File.read("view_named.html.haml")).render(regions)

output = Haml::Engine.new(File.read("layout_named.html.haml")).render do |region|
  region ? regions[region] : unnamed
end
Run Code Online (Sandbox Code Playgroud)

现在变量output包含最终的渲染输出.

请注意,此处的代码并未提供rails附带的所有灵活性,但希望它足以告诉您从哪里开始自定义Haml以满足您的需求.

  • 这是我见过的最全面,写得最好,格式最好的帖子之一.@matt谢谢! (5认同)

Vic*_*roz 5

content = Haml::Engine.new(content_haml).render(
  Object.new, 
  :local_var_1 => ..., 
  :local_var_2 => ...
)


Haml::Engine.new(layout_haml).render(Object.new, :content => content)
Run Code Online (Sandbox Code Playgroud)

layout.haml

!!!
%html
  %head
    %title
  %body
    = content
Run Code Online (Sandbox Code Playgroud)

您也可以使用Object.newhaml中的实例变量(替换为有意义的对象).