`
vwangzhen
  • 浏览: 29742 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

ActionView 的魔术:ERB & Binding 为什么页面上可以用实例变量

阅读更多

Rails 作为一个 MVC 框架,其核心包括三个模块:ActiveRecord,ActionController 和 ActionView。今天这篇博文的主角是 ActionView,解开模板系统的魔术。通常情況下,通过 scaffold 已经能够建立简单的、包含CRUD基本功能的页面,完全不需要手动修改 view 的代码。即使不使用 scaffold ,Rails 也提供了众多的辅助方法,创造一个功能丰富的动态页面简直是易如反掌。但是,会用不代表深入理解,最近有朋友问我这些问题:

  1. 为什么编辑一个对象需要在 Controller 创造一个实例变量
  2. View 通过什么方式访问这些实例变量的
  3. 那么多表单辅助方法,都是需要提供 object_name, method 两个参数,怎么就变成实例变量的值了

相信大部分的 Rails 程序员手边的书都是《Agile Web Development with Rails》,书中提到这一点的时候一笔带过,只是说 Rails 在这里用了一个小魔术。这里,我们就来揭开这个魔术吧!

Part 1. Template Files – 模板文件

当一个 action 需要返回一段 html 片段的时候,我们需要建立一个模板文件。根据不同的版本、请求类型,模板文件的文件名也各不相同,从早期版本的 action_name.rhtml ,到现在的 action_name.text.html.erb ,以及扩展的 rjs,在扩展名中都包含了一个关键字:r / erb。它就是 Rails 模板系统的关键:ERb。

Part 2. ERb – Ruby Templating

ERb – 嵌入式 Ruby (http://ruby-doc.org/stdlib/libdoc/erb/rdoc/index.html ),是 Ruby 语言提供的一个基本扩展。它支持在字符串中嵌入 ruby 代码片段。看上去似乎很神秘,其实我们每天都用到,下面这种形式一定不陌生吧?

<h1><%= @user.name %></h1>

没错,正是因为 ERb 的存在,使得模板中可以动态地引用对象的属性。

 

 

Part 3. Instance Variables of Ruby – Ruby 的实例变量

让我们回顾一下 Ruby 语言的基本要素之一:实例变量。通常我们通过

@time = Time.now

的形式创造一个实例变量。这里我们不重新解释对于“实例变量”的定义,但是必须牢记一点,正如字面所见,实例变量的作用域是当前实例内,也就是说, 只有在实例的内部,才可以直接对实例变量进行读写操作(扩展的访问子方法等等不在讨论范围之内)。那么,为什么 Rails Controller 里创建的实例变量能够在 View 里面访问呢,不是自相矛盾吗?

Ruby 作为一种动态语言,因为其“开放”的特点,使很多原本不可能的编程模式变为可能。比如,通过 Open Class 的特性,你可以动态的为对象注入新的方法定义,或者改写方法的逻辑,或者,通过不同的方法可以在对象的外部访问对象的内部的实例变量。经常使用 console 的朋友可能会了解其中的一种方式:Object#instance_variable_get / Object#instance_variable_set 方法。举个简单的例子:

 

 

 

class User
  def initialize( name )
    @name = name
  end
end

user = User.new( "Jack" )
user.name #=> raise NoMethodError
user.instance_variable_get('@name') #=> "Jack"
user.instance_variable_set('@name', 'Tom')
user.instance_variable_get('@name') #=> "Tom"

 

可以看到,在没有任何访问子的情况下,我们用这种方式对一个实例变量进行读写操作。

除了这种简单的方式,还有另外一种进阶的方式,也是 ERb 常用的一种方式:Binding

 

Part 4. Binding

Binding (http://ruby-doc.org/core/classes/Binding.html ) 是 Ruby 语言的自身的一个特性,在任何对象内,self.binding 方法都会返回一个当前对象关联的 binding 实例。不精确的说,binding 对象可以理解成为当前对象的完整的上下文环境。文档中已经包含了一些示例代码,帮助大家理解 Binding 对象的作用。最重要的一点是:既然是当前对象的完整上下文环境,自然就包括了对象的实例变量。

那么 Binding 在 ERb 中扮演一个什么样的角色?是一个运行环境的提供者。

 

   class Demo
     def initialize(n)
       @secret = n
     end
     def getBinding
       return binding()
     end
   end

   k1 = Demo.new(99)
   b1 = k1.getBinding
   k2 = Demo.new(-3)
   b2 = k2.getBinding

   eval("@secret", b1)   #=> 99
   eval("@secret", b2)   #=> -3
   eval("@secret")       #=> nil
 

回到我们最初的问题,Rails 在 ActionView 中使用了什么样的魔法?答案就是 ERb 和 Binding。首先,获得当前实例的 binding,自然,binding 内也包括了实例变量;紧接着,ERb 允许将模板的内容动态地,绑定到另一个环境中运行。我们依然用刚才的 User 的例子来说明这一点:

 

# A simple template string
template = "Hello, "
user = User.new( "Jack" )
# Get binding
binder = user .send( :binding ) # calling a private method# Rendering template
puts ERB.new( "Hello, <%=@name%>").result( binder )
#=> "Helo, Jack"
puts ERB.new( "Hello,<%=@name%>").result
#=> "Helo, "
 

 

 

虽然例子不是非常恰当,但是足以展示 Binding 和 ERB 的用法。我们可以看到,ERB#result 方法将模板字符串绑定在另外一个环境中运行,而这个环境包含了我们创建的 @user 实例变量,因此,模板中的 @user.name 得到了正确的值。

这就是 ERB 的真面目,也是为什么在 ActionView 中能够访问到 Controller 里实例变量的原因。感叹一下动态语言的强大吧!以上只是非常粗糙的讲述ERB的使用,Rails 所做的魔法远不止如此,如果有兴趣,可以查看 Rails 源代码,对于深入学习 Rails 框架也有很大的好处。

最后,补充一下 ERB 的应用场景。虽然在普通的需求中,ActionView 所做的已经足够,但是某些情况还是需要创造独立的模板系统。比如某个场景,客户要求提供一个完全自定义的模板系统,这个时候 ERB 就大显身手了。只需要将数据源载入实例变量中,并且在使用手册里列出可以访问的方法,即使完全不懂 Ruby 语言也可以写出使用这套简单的模板系统了。

 

来自  http://blog.hozaka.com/?p=20

终于搞明白了 感谢我们的鸡蛋黄大哥(hozaka)的帮助!!!!!!!!!!!

 

 

分享到:
评论

相关推荐

    Ruby中ERB模板的使用

    `binding`返回当前上下文的绑定,使得ERB可以访问到这些变量。`result`方法则负责处理模板并返回最终的HTML字符串。 在提供的文件`txt2.rb`中,可能包含了一个使用ERB处理文本的示例。例如,它可能读取`domain2.txt...

    cells-erb:对单元格的ERB支持

    它不使用实例变量进行输出缓冲。 您应该阅读其文档,以了解使用Erbse可以做什么和不能做什么。 块屈服 使用Erbse,您实际上可以,将它们传递给其他单元格并yield它们。 这将只返回块返回的内容,而不会在后台发生...

    ActionView问题需求跟踪工具 v1.15.1.zip

    5. **表单构建**:ActionView提供了表单构造器,可以自动生成基于模型的表单元素,包括输入字段、选择列表和按钮。 6. **嵌入式Ruby(ERB)和模板引擎**:除了ERB,ActionView还支持其他模板引擎,如Haml、Slim和...

    erb-action:适用于Github Actions的ERB Linter

    适用于Github Action的ERB Linter Github操作,可在项目上运行erb-lint gem。 目录 用法 将以下内容添加到您的Githun操作工作流程中以使用ERB操作: name : Run ERB Linter on : push : branches-ignore : - ' ...

    easy-recycler-binding:ERB是一个库,其中包含一些有用的Kotlin Android数据绑定适配器,用于带有乘以ViewHolders视图的RecyclerView

    使用`ERB`库,你可以轻松地定义不同类型的`ViewHolder`,并使用Kotlin的数据绑定表达式将数据绑定到视图上。数据绑定是Android架构组件之一,它允许开发者以声明式的方式将数据模型与UI元素关联,减少了手动设置UI...

    Laravel开发-erb2blade

    2. **输出转换**:ERB的`&lt;%= %&gt;`用于输出变量,而在Blade中,可以直接使用双大括号`{{ }}`。 3. **模板继承与部分视图**:Blade支持`@extends`和`@section`来实现模板继承,这在ERB中没有直接对应的概念。你需要将...

    task-jst:将模板编译为 JST 文件

    默认情况下,使用 ERB 样式的模板分隔符,更改以下模板设置以使用替代分隔符。 { evaluate : /&lt;&#37;([\s\S]+?)%&gt;/g, interpolate : /&lt;&#37;=([\s\S]+?)%&gt;/g, escape : /&lt;&#37;-([\s\S]+?)%&gt;/g, ...

    erb-lint:检查您的ERB文件中是否有结束标签,缩进,不良属性等

    可以很容易地在ERB文件中引入错误,未关闭的标签,错误的属性名称,错误的缩进。 ERB :: Lint可以通过将ERB标签变成HTML-ish标签并在结果上运行适当HTML linter来检查这些错误: 原始ERB &lt;&#37; if @foo ==...

    ERB-EspWebServer:ERB的Esp8266实验Web服务器

    ERB-EspWebServer /* * This Program Provides the following for the Esp8266 as a WebServer: * But CAUTION, some functionallity may not have been throughly tested. * * The code and effort is always ...

    EmbeddedPowerShell:ERB到PowerShell的端口。 没有明显的原因

    嵌入式PowerShell ERB到PowerShell的端口。 没有明显的原因。 如在所述: EPS1是带有嵌入式PowerShell的纯文本该脚本以类似于嵌入式Ruby模板化(由Puppet使用)的方式处理“ eps1”文件。 所涉及的逻辑并不多-任何...

    极端应答偏差Extremity Response Bias,ERB.doc

    极端应答偏差(Extremity Response Bias,简称ERB)是指个体在使用评定量表进行评估时倾向于选择最极端选项(如7分制量表中的1或7)的一种现象。这种倾向可能是暂时性的,由特定的情境因素引发,例如信息模糊不清、...

    ers:ers - 类似 ERb 的 Rust 模板引擎

    ers - 类似 ERb 的 Rust 模板引擎 ers 是 Rust 的一种 ERb 风格的模板语言。 ers 模板将根据您的意愿转换为静态编译的 Rust 函数,允许您将它们链接到您的其他项目。 图书馆基础设施很大程度上受到了ego启发。 ...

    ActionView问题需求跟踪工具 v1.15.2.zip

    在Rails中,开发者可以使用ERB(Embedded Ruby)或者其他模板语言如HAML或SLIM来创建动态网页。这个工具可能包含了一些实用的功能,比如自动化模板检查,确保代码质量,或者提供一种方式来跟踪哪些模板需要更新以...

    Ruby-Erubi是ruby的ERB模板引擎

    这里的 `binding` 参数是当前上下文,使得模板可以访问到变量。 ### Erubi与其他模板引擎的比较 尽管Erubi提供了简洁和高效的ERB实现,但Ruby社区中还有其他模板引擎,如Haml、Slim和Erbb。它们各有优缺点,适用于...

    Go-ego-一个ERB风格的Go模板语言

    ego是Go语言中的一种模板引擎,它以ERB(Embedded Ruby)风格为灵感,提供了简洁、高效的模板编写方式。ERB是Ruby世界中常见的模板语言,而ego则将其设计理念引入了Go,使得开发者能够利用Go的语法特性来编写模板,...

    ERBFilterBank.zip_erbfilterbank_滤波器组_耳蜗_耳蜗滤波_耳蜗滤波器

    通过使用ERB滤波器组,我们可以将复杂的音频信号分解成多个频带,每个频带对应于人耳对特定频率范围的敏感度。 耳蜗滤波器的设计基于耳蜗内神经元对声音频率响应的非线性特性。耳蜗内的基底膜随着频率的不同会有...

    herbalizer:转换HAML到ERB

    为什么 很多人更喜欢HAML而不是ERB。 但不是每个人,也不是每个情况都如此。 ERB更简单,更容易记住规则,并且对HTML熟悉的人都可以访问。 ERB模板更易于向初学者讲授,并且更易于与广泛的人(例如设计师)进行协作...

    armadillo:使用 ERB 模板继承模板

    一个适用于 ERB 小型库。 用法 要渲染 Armadillo 模板,您需要调用Armadillo.render方法。 此方法接受以下任何选项: :scope - 要绑定到模板范围的任何对象。 :base_path - 要搜索模板的目录的路径。 注意:假定...

    format-erb:VSCode扩展,用于使用htmlbeautifier格式化erb

    标题中的"format-erb"是一个针对Visual Studio Code(VSCode)的扩展插件,它的主要功能是为ERB(Embedded Ruby)文件提供格式化服务。ERB是Ruby on Rails框架中广泛使用的模板语言,它允许在HTML中嵌入Ruby代码,...

Global site tag (gtag.js) - Google Analytics