1

在我正在阅读的“Rails View”书中,有关于演示者的代码

app/helpers/designers_helper.rb

module DesignerHelper
  def designer_status_for(designer = @designer)
    presenter = DesignerStatus.new(designer)
    if block_given?
      yield presenter
    else
      presenter 
    end
  end
end

然后在 show.html.erb

<% designer_status_for do |status| %>
   some html using <%= status %> variable

<% end %>

我很难理解代码块如何获得分配的变量状态以及为什么我们需要在辅助函数中使用“if”语句以及为什么不直接返回演示者变量?

4

3 回答 3

1

让我们从视图开始

<% designer_status_for do |status| %>
   "some html using <%= status %> variable"    
<% end %>

designer_status_for这使用block如下所示的代码调用该方法

designer_status_for {|status| "some html using <%= status %> variable" }

在方法中,

presenter = DesignerStatus.new(designer)
#=>since no `designer` is given it takes the default value of `@designer` 
#  and finds the related presenter

if block_given?
#=> is true since a block is given 

yield presenter
#=> here the method "yields" to the block 
#   i.e. passes the presenter as a variable to the block and executes it. 
#   For e.g. array.map{|x| x+1} works the same way
#   `map` iterates over the array and yields each element to the given block.

{|status|   "some html using <%= status %> variable"}
#=> status is the variable received from method which is presenter
#   This block returns the html to the method that called it

end 
#=>the last statement was yield which was equal to the html returned from block
#  returns the html received from the block 

if方法中的语句是如果给定则返回代码块的结果,否则返回演示者。这允许 DRY 代码,我们需要presenter在代码块中的一堆地方使用变量。

于 2013-09-26T06:30:17.533 回答
1

好的,让我们一步一步来。

@designer首先,您定义一个默认分配的辅助方法。这就是为什么您可以在没有任何参数的情况下调用它的原因:

<% designer_status_for do |status| %>
  # more code

然后,DesignerStatus是实际的演示者,它是与 Designer 不同的类,并创建一个全新的对象,但它有点基于@designer对象。所以,presenter是一个类型的新对象DesignerStatus

block_given?,正如您可能猜到的那样,检查该对象是否应该传递给一个块,或者它是否应该作为普通对象工作。这很可能是您难以理解的棘手部分。所以让我反过来解释一下。你可以这样称呼

designer_status_for.some_presenter_method

在您看来,它会起作用。它可以工作,因为没有给出块并且designer返回了一个对象(换句话说,else触发了该部分),您可以some_presenter_method直接调用该对象。所以,你可以在你的整个视图中使用它,你会没事的。

但是,还有一个更好的选择,即将yield此对象放入一个块中。该yield选项是使此代码片段的原因

<% designer_status_for do |status| %>
  status.some_presenter_method
<% end %>

首先可能。这基本上说的是“获取该演示者对象,将其分配给一个名为的变量status并使该变量可用于块。

所以,如果你现在很难转过头来yield,不要太担心。designer_status_for只需对其自身调用任何方法。在对象本身上使用块的好处是,您的代码变得不那么脆弱,但这是另一个话题。

于 2013-09-26T06:55:13.880 回答
0

发布此问题后,我尝试重新阅读代码并在 irb 中尝试一些示例,以下是回答我问题的发现。

在 Ruby 中,任何方法都可以使用一段代码。例如。

def method_can_take_block?
  answer = 'yes it can take block of code'
end

method_can_take_block? { puts 'this code is not executed but gets passed to method' }

要执行我的代码块,它需要在方法内部产生。只需yield在方法内部调用即可生成代码块。通过显式调用yield,我们可以控制执行代码块的行。

def method_can_take_block?
  answer = 'yes it can take block of code'
  yield
end

method_can_take_block? { puts 'this code gets executed after the variable 'answer' gets assigned with some value.' }

但是,我们在这里没有使用变量“答案”。传递的代码块对函数内部定义的变量没有任何访问权限。因此,为了让块能够访问方法内定义的变量,我们需要让块接受一些参数。注意 |my_answer| 的使用 在下面的代码块中。

   method_can_take_block? { |my_answer| 100.times { puts answer } }

现在我们已经为块添加了一个参数到块,我们需要在调用代码块时传递这个参数。所以这是通过调用yield附加参数来完成的。

def method_can_take_block?
  answer = 'yes it can take block of code'
  yield answer
end

yield answer将答案变量传递给传递给方法的代码块。在这种情况下,answer作为变量在块内传递my_answer,然后打印 100 次。

有了这样的理解,我的问题的回答

  1. 代码块如何获得分配的变量状态:按行yield presenter。这里presenter变量被传递给接收 name 参数的块status

  2. 为什么我们需要在辅助函数中使用'if'语句,为什么不直接返回presenter变量?我们可以避免将整个 erb 作为块传递给方法,但是我们需要在 show.html.erb 的顶部有这样的代码:

<% status = designer_status_for(@designer) %>然后开始使用变量状态。我认为使用块是美学问题,这样我们就可以避免使用赋值。该方法中的 if 语句可以使用这种语法而不是使用块。

于 2013-09-26T06:38:52.267 回答