2010-01-24 108 views
4

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

#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.reverse%>被移除,则输出为“a aa”,表示@display实例变量已由辅助方法设置,但在视图中无法访问它。

如果控制器修改,从而成为(与原始视图代码):

class SampleController < ApplicationController 
    def test 
    display 
    end 
end 

输出成为“AA AAA一个一个”。如果我让它在控制器中显示2个电话,我会得到“aaa aaaa aa aa”。因此,似乎只有在控制器中进行的调用才会修改SampleController实例变量,而视图中的调用将修改视图无法访问的ApplicationController的实例变量。

这是一个在Rails中的错误还是我误解,这是由于某种原因的预期功能?

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

回答

6

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

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

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

+0

因此,在我的真实应用程序中,@display实际上是@user,它用于显示有关用户的信息。举个例子,我的意思是,典型的代码就像<%if logged_in?%><%= @ user.name%><%end%>。那么最好的方法是在ApplicationController中设置@user变量来执行before_filter调用?因为经常,对于给定的视图,@user的唯一用途就像我上面概述的那样,并且没有其他需要在控制器中使用它。 – 2010-01-24 21:48:30

+0

是的,伊娃拷贝机制符合您所描述的内容。在过滤器之前设置@user。 – ffoeg 2010-01-24 21:57:30

+0

谢谢@ffoeg,这个回答非常有帮助。你可以指向任何文档或导轨指南,这是解释? View,Controller和Helpers之间共享什么变量尚不清楚。 – CodeKid 2016-09-17 21:15:48

0

我认为这可能是第二reserved words问题这个星期我见过...

提示:你几乎不必使用Ruby中return关键字。此外,您的defined?使用被吓到我了......可能是值得尝试这样的:

if @display.nil? 
    @display = "a" 
    else 
    @display += "a" 
    end 
+0

你在这里看到什么是保留字问题?无论如何,我猜这不是最基本的问题,因为我最初遇到了使用所有不同单词(登录像我所提到的)的错误以及我在这里生成的代码来弄清楚什么是错误。 感谢您对return语句的提示。 定义?我用过的似乎在做我的意图,但不是吗?我从authlogic的示例实现代码中获得了它,他们将它用于类似的目的。 – 2010-01-24 19:55:53

+0

根据保留字列表,“显示”已知会引起问题。我从来没有听说过在视图中定义实例变量的问题,因为大多数登录模式完全按照您在这里尝试执行的操作,在第一次调用current_user时定义@current_user。界定?在技​​术上会在这里工作,但它通常用于引发错误的事情,而不是如果未定义则返回nil,如局部变量和方法定义。零?适用于实例变量检查的常见情况,并且稍微易于解析。 – tfwright 2010-01-24 20:51:08