`
fanhaipeng
  • 浏览: 8126 次
  • 性别: Icon_minigender_1
  • 来自: 北京
最近访客 更多访客>>
社区版块
存档分类
最新评论

[翻译]167 更多关于虚属性

阅读更多

167:更多关于虚拟属性查看原视频

 

查看英文原版

 

第16集中第一次讲到了虚拟属性。如果你对虚拟属性还不熟悉,你应该先读一下那一集的文字版,或者看那集的视频,将会对你理解本集的内容有帮助。当你要处理的表单非常复杂,里面的字段不能直接对应到你的数据模型的属性上的话,虚拟属性会大显身手。

本集当中,我们将结合回调函数用虚拟属性来给一个博客程序增加标签功能。我们先从下面这个包括一些文章的简单程序开始。 



 

我们要做的是在一个文本框中输入已经存在的、或者新的标签,把他们加到一篇新文章上。虽然已经有很多给 Rails 用的标签插件,但是我们还是打算重头开始实现一个我们自己的方案,利用虚拟属性,这一切都将变的非常容易。

 

 

创建数据模型

 

我们先创建一个 Tag 数据模型。这个数据模型非常简单,只有一个属性, name 。

script/generate model tag name:string

  

TagArticle 数据模型之间必然是有联系的。一篇文章可以有多个标签,一个标签也可以属于多篇文章,这是一种多对多的关系。我们将创建一个用于连接的数据模型,起名叫Tagging 。这个数据模型只有两个整数字段,article_idtag_id ,分别是ArticleTag 数据模型的外部键。

script/generate model tagging article_id:integer tag_id:integer

  

下面,我们执行新建的这两个数据迁移任务来创建这两个新的数据模型。

rake db:migrate

  

接下来我们会很快地在数据模型中来定义这些关系。Tagging 将同时属于(译注:belong_toArticleTag

class Tagging < ActiveRecord::Base   
  belongs_to :article  
  belongs_to :tag  
end 

  

Tag 有一个指向Articlehas_mang :though 的关系。

class Tag < ActiveRecord::Base   
  has_many :taggings, :dependent => :destroy  
  has_many :articles, :through => :taggings  
end  

  

同样,Article 也有一个指向Tag 这样的关系。 

class Article < ActiveRecord::Base
  has_many :comments, :dependent => :destroy
  has_many :taggings, :dependent => :destroy
  has_many :tags, :through => :taggings
  validates_presence_of :name, :content
end

  

注意在TagArticle 数据模型中用到的 :dependent => :destroy 。这将保证,当一个Tag 或者Article 被删除后、任何不被引用的Tagging 也会被删除。 

 

视图

 

搞定了数据模型,我们现在可以修改一下创建新文章的视图,加一个文本框,在里面输入空格分隔的标签,使其与文章关联。因为我们要把文本框中的文字转化为关联关系,所以最简洁的实现方法就是用虚拟属性

<% form_for @article do |form| %>   
  <ol class="formList">   
    <li>   
      <%= form.label :name, "Name" %>   
      <%= form.text_field :name %>   
    </li>   
    <li>   
      <%= form.label :tag_names, "Tags" %>   
      <%= form.text_field :tag_names %>   
    <li>   
      <%= form.label :content, "Content" %>   
      <%= form.text_area :content, :rows => 10 %>   
    </li>   
    <li>   
      <%= form.submit "Submit" %>   
    </li>   
  </ol>   
<% end %>  

添加了tag_names字段的创建新文章的表单

 

我们的Article 数据模型没有一个叫tag_names 的属性,所以我们需要定义一个虚拟属性来表示关联到这篇文章的标签字符串。之前,我们使用读方法和赋值方法来创建虚拟属性的。对于我们的Article 数据模型虽然我们也可以定义一个tag_name= 方法来给文章的标签赋值,但是这种方法有一些缺陷。其中一个缺陷是,无论一篇文章有没有被保存,在赋值函数中创建标签的同时也会创建一个Tagging 记录。

 

更好的做法是使用一个回调函数。在 Article 类中用一个 after_save 的回调函数可以保证只有在一篇文章被保存后它的标签才会被保存。数据模型定义如下所示:

class Article < ActiveRecord::Base   
  has_many :comments, :dependent => :destroy  
  has_many :taggings, :dependent => :destroy  
  has_many :tags, :through => :taggings  
  validates_presence_of :name, :content  
  
  attr_accessor :tag_names  
  after_save :assign_tags  
  
  private   
  def assign_tags   
    if @tag_names  
      self.tags = @tag_names.split(/\s+/).map do |name|   
        Tag.find_or_create_by_name(name)   
      end  
    end  
  end  
  
end  

 

 

我们还是需要为虚拟属性 tag_names 定义读方法和赋值方法,不过我们可以通过访问器(译注: accessor )来定义。当一篇文章被保存后,私有方法 assign_tags 将会被调用,它先看 @tag_names 是不是 nil ,如果不是就把它的值按找到的空格来分割,形成一个数组。然后再用 map 方法迭代这个数组返回每一个标签。 find_or_create_by_name 函数读取一个标签,如果该标签不存在就创建出来。最后我们把这个 Tag 数组赋值给 Article 类的 tags 属性。

 

经过这些数据模型上的修改,我们现在可以新建一篇文章、并给它加一些标签来测试一下我们的代码。

 

 

新建好一篇文章后我们可以用 Rails 的控制台来看看它的标签是不是已经被正确的加上了。

>> a = Article.last
=> #<Article id: 3, name: "New Article", content: "I am a new article.", author_name: nil, created_at: "2009-06-24 20:38:56", updated_at: "2009-06-24 20:38:56">
>> a.tags
=> [#<Tag id: 1, name: "stuff", created_at: "2009-06-24 20:38:56", updated_at: "2009-06-24 20:38:56">, #<Tag id: 2, name: "things", created_at: "2009-06-24 20:38:56", updated_at: "2009-06-24 20:38:56">]

  

没错,两个标签已经被创建并且关联到了我们的文章上。不过我们还没有大功告成,如果我们要编辑这篇文章,我们看到标签文本框里是空的。



 

为了解决这个问题,我们需要改一下Article 数据模型,为tag_names 加一个读方法,这个方法将一篇文章的所有标签以一个字符串的形式返回。因为我们要显式地加一个读方法,所以我们需要把attr_accessor 替换为attr_writer 。 

def tag_names   
  @tag_names || tags.map(&:name).join(' ')   
end 

  

上面的方法里,如果对象变量@tag_names 已经有值,就返回它;如果没有,就把这篇文章所有的标签用空格连接成一个字符串,然后返回。

 

与验证器(译注:Validators)一同工作

 

现在这种实现方法的另一个好处是,它可以和验证器协同工作。如果我们添加了一个标签,同时删除文章的内容使得表单不合法,那么就会有错误信息显示出来,并且标签文本框中的内容还能保持不变。

 

 

因为我们使用了after_save 的回调函数,所以在这篇文章没有被保存前,新标签“etc ”不会被创建。标签以及它和文章的关联关系只有在表单合法并且这篇文章被保存后才会被创建。

现在我们可以很容易地给我们的文章加标签了。如果你的表单比较复杂或者里面有关联到其他数据模型的字段,那么将虚拟属性和回调函数结合起来真的值得一用。

 

  • 大小: 95.7 KB
  • 大小: 42.2 KB
  • 大小: 40.4 KB
  • 大小: 49.2 KB
分享到:
评论
2 楼 fanhaipeng 2010-03-30  
ywencn 写道
Hello
我觉得把"虚属性"改成"虚拟属性"更好理解一点,额。。。

恩,对这个的惯用译法我还不是很熟悉,我这几天有空把这次翻得两篇都改一下
1 楼 ywencn 2010-03-29  
Hello
我觉得把"虚属性"改成"虚拟属性"更好理解一点,额。。。

相关推荐

    关于C#优点的一篇文献翻译

    C#完全支持类和面向对象编程,包括接口和继承、虚函数和运算符重载的处理。这使得开发人员可以使用面向对象的编程思想来设计和实现复杂的应用程序。 基本类型集 C#定义了一个完整的一致的基本类型集,包括整数、...

    关于JAVA领域的外文翻译.doc

    ustrup的C++语言,使得它成为了一个正式的编程标准,为全球的开发者提供了一种更强大、更灵活的编程工具。C++的出现不仅解决了C语言在处理复杂性上的局限,还引入了抽象、封装、继承和多态等核心的面向对象编程原则...

    C#中英文对照翻译7页

    * 属性 (Attribute),提供关于运行时类型的声明性元数据 * 内联 XML 文档注释 * 语言集成查询 (LINQ),提供了跨各种数据源的内置查询功能 与其他 Windows 软件的交互: * 通过互操作,可以与其他 Windows 软件(如...

    beg-csharp-objects-master.zip

    《 Beginning C# Objects: From Concepts to Code》是一本面向初学者的C#编程书籍,主要讲解了C#语言中的面向对象编程...通过阅读和实践这些示例,读者能够更深入地理解面向对象编程的思想,并能将其应用于实际项目中。

    C/C++编译原理的概括

    ### C/C++编译原理概览 #### 编译原理概述 编译原理是计算机科学中的一个重要分支,它主要...随着新技术的不断涌现,编译技术也在不断发展和完善之中,为开发者提供了更多工具和支持,以应对日益复杂的软件开发需求。

    C++面向对象程序设计(第6版)(美)Walter Savitch著,周靖译

    C++通过虚函数和抽象类实现多态性。 7. **模板**:C++的模板功能允许我们编写泛型代码,使代码更具有通用性,可以应用于不同数据类型。 8. **异常处理**:异常处理是C++中处理程序运行时错误的方式,通过try-catch...

    揭密代码结构3

    从高级语言的抽象层次下降到低级的汇编语言,我们可以更深入地理解类的内部工作原理,包括数据成员的布局、方法的调用机制以及多态性的实现。掌握这些底层细节对于编写高效、可维护的面向对象代码至关重要。 标签:...

    2020年7月福建自考网站设计与管理试题及答案解析.docx

    1. 域名解析:域名解析是互联网的一项服务,它作为将域名和IP地址相互映射的一个分布式数据库,能够使人更方便地访问互联网,而无需记住能够被机器直接读取的IP数串。选项C正确,域名解析的主要功能是将域名翻译成IP...

    每天学点C++(C++实例教程:教程+源码)Extern.zip

    继承是创建新类(派生类)的一种方式,新类可以从已有的类(基类)中继承属性和行为。这减少了代码重复,提高了代码重用。C++支持单继承和多继承,其中多继承意味着一个派生类可以从多个基类中继承特性。 多态是指...

    深入探索c++对象模型

    Lippman编著,侯捷翻译的权威书籍,它深入剖析了C++编程语言的核心——对象模型。这本书旨在帮助开发者理解C++背后的底层机制,包括类、对象、继承、多态等概念在内存中的实际表示,以及编译器如何实现这些特性。 ...

    c++物件模型(候捷)

    这本书旨在帮助读者理解C++物件导向语言背后的复杂机制,包括编译器如何处理构造函数、析构函数、虚函数、继承和多态性等概念。下面将对这些关键知识点进行详细阐述。 ### 物件导向语言中的幕后机制 #### 构造函数...

    C++ 程序设计教程的习题答案

    - **抽象**: 从具体事物中提取共同属性和行为,形成更通用的概念。 **3. 翻译方式** - **编译**: 将源代码一次性转换为机器语言,如C++通常使用的编译方式。 - **解释**: 在运行时逐行解析源代码并执行。 **4. ...

    深度探索C++对象模型(简体中文版).pdf

    对象模型是面向对象编程(Object-Oriented Programming,OOP)中的一个核心概念,它描述了对象的结构、属性、方法、以及对象之间的关系。C++作为一种支持面向对象的编程语言,其对象模型则涉及到内存分配、对象的...

    深度探索C++的物件模型

    以上只是《深度探索C++的物件模型》可能涉及的一些基本知识点,实际书籍中可能会更深入地讨论C++的对象模型,包括模板、异常处理、命名空间、内联函数、友元等更多高级主题。学习这本书将有助于读者理解C++的底层...

    深度探索C++对象模型(中&&英文版)

    Lippman著,中文版由JJ.Hou翻译。这本书详细揭示了C++对象模型的内部工作原理,深入剖析了C++语言底层的实现机制,包括类、对象、继承、多态、模板等核心概念在内存中的表示方式。以下是对该书涵盖的一些关键知识点...

    C++面向对象程序设计(第6版)Walter Savitch著 周靖译 课后习题答案

    《C++面向对象程序设计(第6版)》是由著名计算机科学家Walter Savitch撰写,中国计算机专家周靖翻译的一本经典教材。本书深入浅出地介绍了C++语言的面向对象编程思想,是学习C++的必备参考资料。课后习题答案部分则...

    野比经验交流系列0801 - C_ 快速入门

    从给定的文件信息来看,该文档旨在提供C#编程语言的快速入门指南,由英国软件工程师Aisha Ikram撰写,野比翻译。C#,作为.NET Framework的一部分,结合了C++的语法特性、Java的风格以及BASIC的快速开发特性,使其...

    易语言dwmapi模块源码

    易语言是一种基于中文编程的程序设计环境,旨在降低编程门槛,让更多人能够参与到编程的世界中。DWMAPI模块是Windows Desktop Window Manager (DWM) API的一部分,它提供了与Windows Aero Glass效果、窗口组合以及...

Global site tag (gtag.js) - Google Analytics