【问题标题】:Ruby on Rails: Initializing instance variables with helpers in viewRuby on Rails:在视图中使用助手初始化实例变量
【发布时间】:2011-01-08 20:41:18
【问题描述】:

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

#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 我会想到的。如果 被移除,则输出为“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。除非我在控制器中添加不必要的调用,然后再尝试在视图中使用它,否则这将不起作用。

【问题讨论】:

    标签: ruby-on-rails view variables instance helper


    【解决方案1】:

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

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

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

    【讨论】:

    • 所以在我的真实应用中,@display其实就是@user,用来显示用户的信息。作为我的意思的一个例子,典型的代码类似于 。那么最好的方法是在 ApplicationController 中调用 before_filter 来设置 @user 变量吗?因为通常,对于给定的视图,@user 的唯一用途是用于我上面概述的内容,并且没有其他需要在控制器本身中使用它。
    • 是的,ivar 复制机制符合您的描述。在前置过滤器中设置@user。
    • 谢谢@ffoeg,这个答案很有帮助。您能否指出任何解释这一点的文档或 Rails 指南?目前尚不清楚 View、Controller 和 Helpers 之间共享哪些变量。
    • 据我所知,此类指南不存在。我在单步调试代码以调试另一个问题时发现了这一点。抱歉回复晚了。
    【解决方案2】:

    我想这可能是我本周看到的第二个reserved words 问题...

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

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

    【讨论】:

    • 您在这里看到的保留字问题是什么?无论如何,我猜这不是根本问题,因为我最初使用所有不同的词(如我提到的登录内容)和我生成的代码在这里遇到了这个错误,以找出到底出了什么问题。感谢您提供有关退货声明的提示。定义的?我用过的似乎正在做我想做的事,不是吗?我从 authlogic 的示例实现代码中得到它,他们将它用于类似目的。
    • 根据保留字列表,已知“display”会导致问题。我从来没有听说过在视图中定义实例变量的问题,因为大多数登录模式完全按照您在此处尝试做的事情,在第一次调用 current_user 时定义 @current_user。定义?在技​​术上可以在这里工作,但它通常用于引发错误而不是在未定义时返回 nil,例如局部变量和方法定义。零?适用于非常常见的实例变量检查情况,并且更容易解析。
    猜你喜欢
    • 2011-07-13
    • 1970-01-01
    • 2022-01-18
    • 2011-06-21
    • 2017-04-05
    • 1970-01-01
    • 1970-01-01
    • 2012-09-13
    • 2015-03-03
    相关资源
    最近更新 更多