Rails view_context

Posted

技术标签:

【中文标题】Rails view_context【英文标题】: 【发布时间】:2022-01-20 02:25:23 【问题描述】:

我无法理解 view_context。我目前正在我的应用程序中实现数据表,参考来自this video。

我不明白的是如何访问 view_context 的内容,即传递给数据表类。

  def index
    respond_to do |format|
      format.html
      format.json  render json: UsersDatatable.new(view_context) 
    end
  end

然后我在我的数据表类中访问它

  def initialize(view)
    @view = view
  end

我正在使用一个名为 subscribem 的 gem。我声明了一个 Subscribem::Account 并将变量 current_account 传递给每个视图。在数据表类中我可以像这样访问它

  def initialize(view)
    @view = view
    @current_account = @view.current_account
  end

但问题是在控制器中,我添加了一些变量,例如

  def index
    @date = DateTime.now #or date=DateTime.now
    respond_to do |format|
      format.html
      format.json  render json: UsersDatatable.new(view_context) 
    end
  end

我无法获取过去的日期或@date。

  def initialize(view)
    @view = view
    @current_account = @view.current_account
    @date = @view.date
  end

提前谢谢好兄弟/姐妹

【问题讨论】:

【参考方案1】:

理解视图上下文的关键是真正了解像 ERB 这样的模板引擎是如何工作的(它们在高层次上的工作方式几乎相同)。

您获取一个字符串(或缓冲区)和一个上下文,该上下文是您要插入到视图中的数据以及您可能想要使用的所有方法。

举个简单的例子:

require 'erb'

class Person
  def initialize(first_name, last_name)
     @first_name = first_name
     @last_name  = last_name
  end

  def get_binding
    binding
  end
end

template = "Hello my name is <%= @first_name %> <%= @last_name %>"
person = Person.new('John', 'Doe')
erb = ERB.new(template)
puts ERB.new(template).run(person.get_binding) # Hello my name is John Doe

由于我们使用Person 实例内部的绑定运行模板引擎,我们可以访问它的实例变量。它本质上与视图上下文的工作方式相同。这种“魔法”就是控制器的实例变量如何在视图和帮助程序中可用,以及为什么初学者最终会将它们与全局变量混淆。

但是在其他情况下,例如装饰器或序列化器封装仍然适用。 @date = DateTime.now 仍然是控制器的实例变量,如果你想访问它,你需要使用 instance_variable_get 来违反封装:

def initialize(view)
  @view = view
  @current_account = @view.current_account
  @date = @view.instance_variable_get(:'@date')
end

声明一个访问器:

class UsersController
  attr_reader :date

  def index
    @date = DateTime.now #or date=DateTime.now
    respond_to do |format|
      format.html
      format.json  render json: UsersDatatable.new(view_context) 
    end
  end
end

class UsersDatatable
  def initialize(view)
    @view = view
    @current_account = @view.current_account
    @date = @view.date
  end
end

或者改变你的类的接口,这样它就不需要插入另一个对象。

class UsersDatatable
  def initialize(view, date: nil)
    @view = view
    @current_account = @view.current_account
    @date = date
  end
end

【讨论】:

非常感谢。我理解数据如何从控制器传递到模板引擎/视图的概念。为什么根据我的代码无法获得数据是由于封装的原因?我还没有尝试过声明访问器的方式,但是我使用会话参数来存储数据,并且可以在数据表类中访问它。这是个好方法吗? 并非如此。会话主要用于跨请求存储数据。由于它存储在 cookie 中,因此您还必须非常小心以避免溢出,因为它的大小非常有限。在其他方面,它非常类似于使用全局变量。我会向初始化程序添加参数并显式传递数据。

以上是关于Rails view_context的主要内容,如果未能解决你的问题,请参考以下文章

markdown [rails:devise] Ruby on Rails的身份验证gem。 #ruby #rails

Rails:如何在 Rails 中为 Devise 设置密钥?

从 Rails 2 到 Rails 3 路由

Rails:在 Rails 控制器中捕获所有异常

如何在带有 Rails 4.2 的专用调试端口上使用工头启动 Rails?

Rails 4 的 Rails_admin 批量分配错误