html.erb 中可以访问哪些控制器数据?

what controller data is accessible in html.erb?

我正在尝试了解 class 中的控制器 class 和 .html.erb 视图文件如何连接,以及如何连接视图访问控制器方法中的数据。例如,我有以下控制器 class:

class SomeController < ApplicationController 

   def show
     # defining some data to access in the view
     x = 1
     @y = 2
   end

end

如果在相应的.html.erb视图文件中,我尝试访问@y,这很好

<p> <%= @y %> </p>

但是,如果我尝试访问 x,它会报错

<p> <%= x %> </p>

undefined local variable or method 'x'

从概念上讲,为什么 @y.html.erb 视图中是可访问的,但 x 不是。

PS:我应该补充一点,我知道带有 @ 的变量表示 Ruby 中的实例变量,所以(我认为)@y将是 SomeController 实例的实例变量。但是,我不清楚这会如何影响 .html.erb 视图文件从 SomeController.

访问的内容

在 RoR 中,如果您在控制器中将变量声明为实例变量 @y,则它可用于您的视图。 另一方面,x 是局部变量,只能在其范围内访问。

根据您的示例,控制器中的 @y 与视图中的 @y 不同,但是在非常高的级别上它们似乎是相同的。 Rails 在幕后做了很多魔术,正如您已经知道的(如果不是),Rails 相信约定优于配置,在这一点上 Rails 将查找 controller 中的所有 instance variables 并将它们复制到 views,即使假设您不想要它们,它也会在那里。 Rails 将所有实例变量公开给相应的视图。 到目前为止,这是我的理解,如果我遗漏了什么,请补充更多细节。

关于变量:

  • foo = 'bar' # 这意味着你声明了一个局部变量,不能从视图中访问

  • @foo = 'bar' # 意味着你声明了一个 instance_variable,这将在视图中可用

您还可以在执行的控制器上定义 helper_method 和 returns 一些数据,例如 helpers.

根据上面的描述和答案,很明显可以在视图中访问实例变量。

回答下面提到的问题

Conceptually, why @y is accessible in the .html.erb view, but x is not.

在呈现视图时,实例变量及其值从控制器获取并传递给视图初始化器,视图初始化器将它们分配给视图实例。

这是使用这些 ruby 方法完成的:

instance_variables - gets names of instance variables  
instance_variable_get(variable_name) - gets value of an instance variable 
instance_variable_set(variable_name, variable_value) - sets value of an instance variable 

[https://github.com/rails/rails/blob/0c5552a3dd28e35cce64462765cc41c5355db0f1/actionpack/lib/abstract_controller/rendering.rb#L138-L145][1]

在上面link方法中命名为

"view_assigns" -> collects the controller instance variable
"view_context passes" -> them to the views
"assign(new_assigns)" -> setting them in the view

这是一个范围问题(范围定义了程序中变量的访问位置)。 Ruby有四种变量作用域,localglobalinstanceclass.

你的情况:

  • x 是局部变量,它们在声明它们的代码(方法、循环等)中是局部的。
  • @y是一个实例变量,它们在定义它的class实例中的任何地方都是可见的。

如果您明确将其提供为本地,则可以访问 x

def show
   render locals: {
      x:  1
   }
end

在视图中使用变量的推荐方法是使用 instance variables。那是因为如果你尝试使用 local variable 而你没有传递一个值,你会得到一个错误。但是使用 instance variables,你会得到 nil.

有关如何在视图中使用 local variables 的更多信息,您可以查看 link.