Rails宝典之第八式: layout与content_for [转] (2/462)

本帖地址: 复制地址

楼主: CMO涔漠

用户形象图片

Rails宝典 Layout详解

关键字:   Rails layout content_for    

如果我们想根据模板页面更改局部layout,使用content_for即可。
content_for允许模板页面代码放到layout中的任何位置。

比如我们的Rails程序不同的页面有不同的css样式,我们可以在layout里留出位置:

代码
  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"   
  2.   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">  
  3. <html>  
  4.   <head>  
  5.     <title>Todo List</title>  
  6.     <%= stylesheet_link_tag 'application' %>  
  7.     <%= yield :head %>  
  8.   </head>  
  9.   <body>  
  10.     <div id="container">  
  11.       <h1>Todo List</h1>  
  12.       <%= yield %>  
  13.     </div>  
  14.   </body>  
  15. </html>  

我们用yield :head来给模板页面某段代码留个"座位",再看页面:
代码
  1. <% content_for :head do %>  
  2.   <%= stylesheet_link_tag 'projects' %>  
  3. <% end %>  
  4. <h2>Projects</h2>  
  5. <ul>  
  6. <% for project in @projects %>  
  7.   <li><%= project.name %></li>  
  8. <% end %>  

content_for :head里面的代码将填充layout里的yield :head。
layout+content_for,很灵活吧。
回到帖子顶部

1楼[楼主] CMO涔漠

用户形象图片

这次的视频很有用,详细解释了layout的用法 
一般来说layout有如下五种: 
gobal layout,controller layout,shared layout,dynamic layout,action layout

假设我们有一个views/projects/index.rhtml页面: 


代码
<h2>Projects</h2>  
<ul>  
<% for project in @projects %>  
  <li><%= project.name %></li>  
<% end %>  
</ul>  


下面来看看各种layout的用法。

1,global layout 
添加views/layouts/application.rhtml: 


代码
<h1>Application Layout!</h1>  
<%= yield %>  


在layouts目录下添加application.rhtml即可,<%= yield %>即输出我们的projects/index.rhtml页面 
由于我们的controller都继承自ApplicationController,所以application.rhtml会先解析

2,controller layout 
添加views/layouts/projects.rhtml: 


代码
<h1>Projects Layout!</h1>  
<%= yield %>  


道理同上,ProjectsController当然会使用同名的projects.rhtml作layout了 
注意的是controller layout会覆盖global layout

3,shared layout 
添加views/layouts/admin.rhtml: 


代码
<h1>Admin Layout!</h1>  
<%= yield %>  


我们建立了admin layout,然后在需要使用该layout的controller中指定即可: 

代码
class ProjectsController < ApplicationController   
  layout "admin"  
  
  def index    
    @projects = Project.find(:all)   
  end   
end   


4,dynamic layout 
有时候我们需要根据不同的用户角色来使用不同的layout,比如管理员和一般用户,比如博客换肤(也可以用更高级的theme-generator) 


代码
class ProjectsController < ApplicationController   
  layout :user_layout   
  
  def index   
    @projects = Project.find(:all)   
  end   
  
  protected  
  
  def user_layout   
    if current_user.admin?   
      "admin"  
    else  
      "application"  
    end   
  end   
end   


5,action layout 
在action中指定layout即可: 


代码
class ProjectsController < ApplicationController   
  layout :user_layout   
  
  def index   
    @projects = Project.find(:all)   
    render :layout => 'projects'   
  end   
  
  protected  
  
  def user_layout   
    if current_user.admin?   
      "admin"  
    else  
      "application"  
    end   
  end   
end   


上面的index方法指定使用projects layout,当然我们也可以指定不使用layout,如printable页面: 

代码
def index   
  @projects = Project.find(:all)   
  render :layout => false  
end   


需要注意的是,这5种layout会按顺序后面的覆盖前面的layout

关于erb和capture的文章:http://hideto.javaeye.com/blog/97353
回到帖子顶部

2楼[楼主] CMO涔漠

用户形象图片

ActionView:七,capture_helper 
关键字: rails   Rails ActionView capture_helper 源码     
Struts有Tiles,WebWork可以用sitemesh,而Rails呢?有Capture! 
请看活生生的例子先: 
例子1: 


代码
#  layout.rhtml:   
  
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">  
<head>  
  <title>layout with js</title>  
</head>  
<body>  
  <%= @greeting %>  
</body>  
</html>  
  
#  view.rhtml:   
  
<% @greeting = capture do %>  
  Welcome To my shiny new web page!   
<% end %>  


使用capture方法可以extract任何东西到一个实例变量里(如@greeting),这样就可以在你的模板其他地方甚至layout中使用它了

例子2: 


代码
#  layout.rhtml:   
  
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">  
<head>  
  <title>layout with js</title>  
  <script type="text/javascript">  
    <%= yield :script %>  
  </script>  
</head>  
<body>  
  <%= yield %>  
</body>  
</html>  
  
#  view.rhtml:   
  
<% content_for("script") do %>  
  alert('hello world')   
<% end %>  


使用content_for方法也是封装一段html或者javascript或者什么东西,这样可以得到一个变量(如@content_for_script),我们可以在layout中 
使用<%= yield :script %>或者<%= @content_for_script %>来使用

好了,看看代码capture_helper.rb: 


代码
module ActionView   
  module Helpers   
    module CaptureHelper   
  
      def capture(*args, &block)   
        begin   
          buffer = eval("_erbout", block.binding)   
        rescue   
          buffer = nil   
        end   
        if buffer.nil?   
          capture_block(*args, &block)   
        else  
          capture_erb_with_buffer(buffer, *args, &block)   
        end   
      end   
  
      def content_for(name, content = nil, &block)   
        eval "@content_for_#{name} = (@content_for_#{name} || '') + capture(&block)"  
      end   
  
      private  
        def capture_block(*args, &block)   
          block.call(*args)   
        end   
         
        def capture_erb(*args, &block)   
          buffer = eval("_erbout", block.binding)   
          capture_erb_with_buffer(buffer, *args, &block)   
        end   
         
        def capture_erb_with_buffer(buffer, *args, &block)   
          pos = buffer.length   
          block.call(*args)   
          data = buffer[pos..-1]   
          buffer[pos..-1] = ''  
          data   
        end   
         
        def erb_content_for(name, &block)   
          eval "@content_for_#{name} = (@content_for_#{name} || '') + capture_erb(&block)"  
        end   
         
        def block_content_for(name, &block)   
          eval "@content_for_#{name} = (@content_for_#{name} || '') + capture_block(&block)"  
        end   
    end   
  end   
end   


我们看到content_for实际上是对capture方法的封装,并生成一个以content_for开头的实例变量,而且content_for可以重复定义同一name,这样content会累加 
相关文章不可小视的ERB和capture 
回到帖子顶部
个人信息
  • 荣誉+3
  • 荣誉+2
  • 荣誉+1
  • 荣誉-1
  • 荣誉-2
  • 荣誉-3
发表留言
  • 文章不错!
  • 精华好文!
  • 支持原创文章!
  • 帖子图文并茂,好!
  • 真知灼见,说得好!
  • 恶意广告
  • 违规内容
  • 严重灌水
  • 重复发帖
  • 标题党
你确定要删除此楼层吗
扣20点经验值