4

我遇到了某种类型的范围问题,它阻止了实例变量被从视图中调用的助手正确初始化。

#sample_controller.rb
class SampleController < ApplicationController
  def test
  end
end

#application_controller.rb
helper_method :display 
def display
  if not defined? @display
    return @display = "a"
  else
    return @display += "a"
  end
end

#test.html.erb
<%= display %>
<%= display %>
<%= @display %>
<%= @display.reverse %>

当显示样本/测试时,它会因“在评估 nil.reverse 时”出现错误而死亡。这是令人惊讶的,因为前两次 display 调用应该已经初始化 @display 我会想到的。如果 <%= @display.reverse %> 被删除,则输出为“aa a”,表示 @display 实例变量正在由辅助方法设置,但在视图中无法访问它。

如果控制器被修改为(使用原始视图代码):

class SampleController < ApplicationController
  def test
    display
  end
end

输出变为“aa aaa a a”。如果我让它在控制器中显示 2 次调用,我会得到“aaa aaaa aaa aa”。所以看起来只有控制器中的调用会修改 SampleController 实例变量,而视图中的调用会修改视图无权访问的 ApplicationController 的实例变量。

这是 Rails 中的错误还是我误解了,这是出于某种原因预期的功能?

我遇到这个错误的上下文是试图创建一个logged_in?ApplicationController 方法在第一次调用它时设置一个@user 变量,如果用户登录则返回true 或false。除非我在控制器中添加不必要的调用,然后再尝试在视图中使用它,否则这将不起作用。

4

2 回答 2

6

渲染时有两个@display ivars,一个在控制器中,一个在视图中。视图无法访问控制器中的视图,反之亦然。在渲染开始时,Rails 将所有控制器 ivars 复制到视图中。但当时@display 不存在,也没有被复制过来。在任何 ruby​​ 程序中,对 @my_undefined_ivar 的调用将返回 nil - 这正是发生在您身上的事情。

可能会令人困惑,这里是另一种说法。Rails 在渲染开始时将 ivars 从控制器复制到视图中。因此,视图 ivar 中的更改不会反映在控制器 ivar 中,反之亦然。您定义的帮助器允许视图调用控制器上的方法,因此控制器的 ivar 可以作为返回值传递回视图,但对控制器 ivar 本身的更改不会反映在另一个视图的 ivar 中。

在这种情况下,只需使用辅助方法并忘记视图中的 @display 即可。

于 2010-01-24T21:33:23.043 回答
0

我想这可能是我本周看到的第二个保留字问题......

提示:您几乎不需要return在 Ruby 中使用关键字。此外,你的使用defined?让我感到害怕......可能值得尝试一下:

  if @display.nil?
    @display = "a"
  else
    @display += "a"
  end
于 2010-01-24T19:35:05.947 回答