用户形象图片

转: http://www.rorchina.net/?14/viewspace-1656.htm

================================================

 

《Web开发敏捷之道(第二版)》这本书已经买了好几个月了,但真正开始系统的学习还是这阵子的事儿。今天改写了书中一段不爽的例子,如下:

在介绍购物车的演示代码中(Page127),有如下例子:

------------------------------------------------------------------------------------------

<%= hidden_div_if(@cart.items.empty?, :id => "cart") %>
    <%= render(:partial => "cart", :object => @cart) %>
</div>


module StoreHelper
def hidden_div_if(condition, attributes = {})
    if condition
      attributes["style"] = "display: none"
    end

    attrs = tag_options(attributes.stringify_keys)

    <div #{attrs}>
end
end


------------------------------------------------------------------------------------------

模板代码的味道相当的不好,何出此言?明摆着半个</div>在外面放着,不恶心才怪,可见这些Rails专家写的代码并不能全信。

如果能像下面这样调用就爽了:

<% hidden_div_if(@cart.items.empty?, :id => "cart") do %>
    <%= render(:partial => "cart", :object => @cart) %>
<% end %>


我们就按照这个目标重构,请看大屏幕:

module StoreHelper
def hidden_div_if(condition, attributes = {}, &block)
    if condition
      attributes["style"] = "display: none"
    end

    attrs = tag_options(attributes.stringify_keys)

    content = capture(&block)

    concat("<div #{attrs}>", block.binding)
    concat(content, block.binding)
    concat("</div>", block.binding)
end
end

搞定了!F5浏览一下吧。

================================================================

RoR相关API介绍:

concat(string, binding)
The preferred method of outputting text in your views is to use the <%= "text" %> eRuby

syntax. The regular puts and print methods do not operate as expected in an eRuby code

block. If you absolutely must output text within a code block, you can use the concat

method.

<% concat "hello", binding %>
is equivalent to using:

<%= "hello" %>

# File vendor/rails/actionpack/lib/action_view/helpers/text_helper.rb, line 25
25:       def concat(string, binding)
26:         eval(ActionView::Base.erb_variable, binding) << string
27:       end


capture(*args, &block)
Capture allows you to extract a part of the template into an instance variable. You can use

this instance variable anywhere in your templates and even in your layout.

Example of capture being used in a .rhtml page:

<% @greeting = capture do %>
    Welcome To my shiny new web page!
<% end %>
Example of capture being used in a .rxml page:

@greeting = capture do
    'Welcome To my shiny new web page!'
end

# File vendor/rails/actionpack/lib/action_view/helpers/capture_helper.rb, line 56
56:       def capture(*args, &block)
57:         # execute the block
58:         begin
59:           buffer = eval(ActionView::Base.erb_variable, block.binding)
60:         rescue
61:           buffer = nil
62:         end
63:        
64:         if buffer.nil?
65:           capture_block(*args, &block).to_s
66:         else
67:           capture_erb_with_buffer(buffer, *args, &block).to_s
68:         end
69:       end

参考:C:\ruby\lib\ruby\gems\1.8\gems\actionpack-1.13.5\lib\action_view\helpers\form_tag_helper.rb

回到帖子顶部