ruby-on-rails – 如何在rails中创建语义布局的专用构建器?

这就是我想在index.html.erb中编写标记的方式

<%= page_for "Super Cool Page" do |p| %>
    <%= p.header do %>
        Ruby is Cool
    <% end %>
    <%= p.body do %>
        Witty discourse on Ruby.
    <% end %>
    <% if page.has_sidebar? %>
        <%= p.sidebar do %>
            <ul><li>Option 1</li></ul>
        <% end %>
    <% end %>
<% end %>

哪个会输出

<div class="page">
    <header><h1>Super Cool Page</h1></header>
    <section>
    Witty discourse on Ruby.
    </section>
</div>

当page.has_sidebar?是真的

<div class="page">
    <header><h1>Super Cool Page</h1></header>
    <asside><ul><li>Option 1</li></ul></asside>
    <section>
    Witty discourse on Ruby.
    </section>
</div>

我已经看过rails中的FormHelper类以获得指导,但似乎我必须复制我正在努力避免的大量工作.我只是想弄清楚在框架中挂起类/模块/方法的位置以及对象| p |的类型应该.

我的第一个倾向是创建一个实现header,body和sidebar方法的PageBuilder类.但是我被困在渲染管道上以使所有输出正确.

是否有一个已经提供此类语义生成的gem?如果不是,我会喜欢任何关于如何设置它的见解.

最佳答案 我在模板中使用类似的东西.这是一个修改.这应该适用于Rails 3.

application_helper.rb:

module ApplicationHelper
  class PageBuilder
    def initialize(title, template)
      @title, @template = title, template
      @header, @body, @sidebar = nil, nil, nil
      @options = { :page => {} , :header => {}, :sidebar => {}, :body => {}, :title => {} } 
      @logger = Rails.logger
    end
    def parse(&block)
      if block_given?
        if @template.respond_to?(:is_haml?) && @template.is_haml?
          contents = @template.capture_haml(&block) 
        else
          #erb
          contents = @template.capture(&block)
        end
      else
        contents = ""
      end
      contents
    end

    def page (options,&block)
      options[:class] ||= "page"
      @options[:page] = options
      parse(&block)
      content = ""
      content += @template.content_tag(:title, @options[:title]) { @title } unless @title.nil?
      content += @template.content_tag(:header,@options[:header]) do
        @template.content_tag( :h1) { @header } 
      end unless @header.nil?
      content += @template.content_tag(:asside, @options[:sidebar]) { @sidebar } unless @sidebar.nil?
      content += @template.content_tag(:section, @options[:section]) { @body } unless @body.nil?
      return @template.content_tag(:div, @options[:page]) { content.html_safe }
    end
    def header(options={},&block)
      @options[:header] = options
      @header = parse(&block)
      nil
    end
    def sidebar(options={},&block)
      @options[:sidebar] = options
      @sidebar = parse(&block)
      nil
    end
    def body(options={},&block)
      @options[:body] = options
      @body = parse(&block)
      nil
    end
  end

  def page_for(title, options = {}, &block )
    raise ArgumentError, "Missing block" unless block_given?
    builder = PageBuilder.new(title, view_context )
    return builder.page(options) do 
      block.call(builder)
    end
  end
end

现在,在您的示例代码中,当page.has_sidebar? == false,你会得到的

<div class="page"><title>Super Cool Page</title><header><h1>
    Ruby is Cool
</h1></header><section>
    Witty discourse on Ruby.
</section></div>

当page.has_sidebar? ==是的,你会得到的

<div class="page"><title>Super Cool Page</title><header><h1>
    Ruby is Cool
</h1></header><asside>
      <ul><li>Option 1</li></ul>
</asside><section>
    Witty discourse on Ruby.
</section></div>

您可以在页面方法中重新排列内容以获得任何所需的布局作为输出.

点赞