开发人员:Ruby on Rails
为 Oracle 和 Ruby on Rails 添加标签作者:Matt Kern
澄清概念,为 Oracle+Rails 应用程序添加标签和标签群。 2007 年 6 月发表 在过去的几年里,社会计算席卷了互联网,而这个趋势的特征之一就是“标签”的概念。标签虽然算不上是新概念,但它最新的应用具有新颖性 - 至少对于 Web 应用程序领域是这样的。共享标签数据让最新一轮 Web 应用程序的用户以前所未有的方式搜索和共享数据。 标签本身并不会给您的 Rails 应用添加惊人的功能,但是您在标签基础上构建的特性会给您的用户增加一层丰富的体验。您会发现自己很快就沉迷于那些利用少量简单字符串的新特性了。 本文将介绍使用 acts_as_taggable_on_steroids 插件为您的站点添加标签功能是何等的简单。 混淆泛滥信不信由你,为您的 Rails 应用添加标签最棘手的地方在于确定使用哪个库。实现 acts_as_taggable 概念有多种竞争性的方法。截止到本文写作之际,至少有四种宣传过的在 Rails 应用中实现标签的方法:
下面,让我们来逐个查看这些方法并试着理清一个非常混乱的情形。 acts_as_taggable gem。 这个 gem 是为 Rails 编写的首个实现,因此,它实际上针对的是比 1.0 更老的版本。它对当前的 Rails 版本(1.1,1.2 以及 Edge Rails -“Edge Rails”是运行最新的或是顶级版本 Rails 时所用的一个新奇术语)仍有效。该 Gem 有一个十分致命的弱点,因此在 Rails 应用中不会被采用。它要求为您想要添加标签的每个模型提供一个单独的连接表。但是,如果您只想要为一个模型添加标签,这可能是最简单的方法。虽然您可以为多个模型添加标签,但需要为添加标签的每个模型创建一个单独的连接表和关联,这样就大大增加了开销。 acts_as_taggable 插件。 此插件(相对于 gem)是由 Rails 的创建者 (David Heinemeier Hanson) 编写的。它的实现采用了 Rails 较新版本中一些更高级的特性,如 :has_many_through 和多态关联。它有个良好的开端,但是 Hanson 自己却承认该插件尚不成熟,而且 Rails 核心团队已经决定不应用由 Rails 社区提交的大量补丁。(据我所知,甚至还有一个报告的 SQL 注入漏洞在官方版中没有解决。)然而,它可能是最容易安装和使用的实现,您也许会有兴趣了解。它可以通过 Rails SVN 服务器直接访问,所以您只需要调用 $ script/plugin install acts_as_taggable 遗憾的是,据 Rails 核心开发人员讲,此插件的目的仅在于概念验证,它存在不少问题。 acts_as_taggable_on_steroids plugin。 尽管从这个插件的名称上看好像它是在原先 acts_as_taggable 插件之上构建的附加功能,但事实并非如此。它是对原先插件的重写,而且确实添加了测试和一些额外功能。最让人疑惑不解的是 acts_as_taggable gem 的原作者发布了一篇名为"Tagging on Steroids with Rails"的网志。哟!(我们将关注这个插件,因为“官方的”Rails 插件不是用于生产的。) has_many_polymorphs 插件。 has_many_polymorphs 在同类中相对年轻,它是个更抽象、非常强大的插件,可用于给模型添加标签,尽管它并不是专门为此目的构建的。以后我们再介绍 has_many_polymorphs 插件解决的一些问题;现在,我想要介绍的是 acts_as_taggable_on_steroids,因为它对于 Rails 的开发新手来说更简明、更易用。多态关联是 Rails 的高级内容,尽管在 acts_as_taggable_on_steroids 插件中有大量应用,但不必完全理解它们。 安装首先,阅读我的文章“Ruby on Rails 移植指南”。通过这篇文章,您会了解如何利用 Rails Migrations 为一个叫做 Discographr 的在线社会音乐编目应用程序创建数据库模式。下文都以此应用程序为基础。 我们先试验 acts_as_taggable_on_steroids 插件。官方 Rails SVN 不包含这个插件,因此您要先找到它。Rails 有一个便捷的 script/plugin 命令,可以帮您找到该插件: $ script/plugin discover -l | grep viney http://svn.viney.net.nz/things/rails/plugins/ 插件发现脚本搜索 wiki.rubyonrails.org/rails/pages/Plugins wiki 页面,获得所有已知的插件信息库。现在将信息库添加到您的已知源列表: $ script/plugin source http://svn.viney.net.nz/things/rails/plugins/ 这能让您执行异常简单的命令: $ script/plugin install acts_as_taggable_on_steroids 已经完成了: $ script/plugin install \ http://svn.viney.net.nz/things/rails/plugins/acts_as_taggable_on_steroids/ 然而,如果 Rails 在其他项目中已知此信息库,则会更简单。(您还可以使用一个称为 rapt 的工具搜索和下载插件。可在 RubyForge 找到此工具。) 快速浏览并确定已将插件安装到 RAILS_ROOT/vendor/plugin 目录下。 然后,您需要更改数据库使其支持该插件并允许您为模型添加标签。您可使用 Migrations 完成这项工作,就像在“Ruby 大移植”中所述那样): $ script/generate migration AddTags exists db/migrate create db/migrate/004_add_tags.rb
def self.up create_table :tags do |t| t.column :name, :string end create_table :taggings do |t| t.column :tag_id, :integer t.column :taggable_id, :integer t.column :taggable_type, :string t.column :created_at, :datetime end end 这次移植添加了两个表。第一个表为 tags,它存放实际的标签名称。第二个表将这些标签与一个模型关联起来。该插件使用 taggable_type 字段做表名(利用 Rails 标准的复数化和单数化神奇功能),并按主键查找目标。还可以告诉你的是,该移植直接出自该插件自带的测试。测试是 acts_as_taggable_on_steriods 插件向 DHH 版本添加的几个特性之一。 查看 RAILS_ROOT/vendor/plugins/acts_as_taggable_on_steroids/test,您就能找到为该插件编写的所有测试。测试不仅起到很好的安全网的作用,还能让您自由地修改代码(知道您经常运行 rake 测试发现缺陷),此外还提供了库的典型使用案例。这就像写入文档中一样好用!因此,通过查看 test 目录下的 schema.rb 文件,您就知道插件需要什么才能使用了。 接下来,您需要运行移植真正将所需的表添加到模式中: $ rake db:migrate (in /Users/mattkern/dev/discographr) == AddTags:migrating ========================================================= -- create_table(:tags, {:force=>true}) -> 0.7773s -- create_table(:taggings, {:force=>true}) -> 1.0804s == AddTags:migrated (1.8754s) ===============================================搞定,就这么简单。现在您就可以给模型添加标签了。
玩转标签现在是使用新增功能的时候了。首先您需要给模型添加一个 acts_as helper。因为希望 Discographr 中所有的模型都可添加标签,所以您需要给每个模型添加一行。Rails 利用 acts_as helpers 添加功能或扩展 ActiveRecord::Base 类和子类。举例来说,acts_as_taggable 在一个调用中为您的模型添加标签功能(理论上的),而 acts_as_tree 为您的模型添加层级树功能。从给 Artist 模型添加标签开始。 class Artist < ActiveRecord::Base acts_as_taggable end这个简单的声明为 Artist 模型添加了大量功能。它首先是用 Taggings 和 Tags 模型创建 :has_many 关系。但您会说“等等”。您还没定义这些模型呢!这就是使用插件的特性之一。在 plugin 目录下查看最新安装的插件,您会看到两个模型文件 tag.rb 和 tagging.rb。通过将这些模型放在插件的 lib 目录下而将其包含到应用程序中。但是,在这里我是还要提出一个警告:虽然在插件中定义模型很方便,但这也会产生问题。因为这样做可能会与所包含的应用程序模型发生冲突。 如果您以前使用过 Rails,您就会知道 :has_many、:has_one 和 :has_and_belongs_to_many 方法会为您的模型添加许多方法。由于插件依赖 :has_many 方法和多态关联,因此可以通过将模型声明为 acts_as_taggable 获得所有功能。稍后您会看到添加的这些方法的使用情况。 好了,继续为 Discographr 的其他模型添加标签。因为希望能为已定义的所有模型添加标签,所以您需要为 Album 和 Song 模型添加 sacts_as_taggable 调用: class Album < ActiveRecord::Base belongs_to :artist acts_as_taggable end class Song < ActiveRecord::Base belongs_to :album acts_as_taggable end 现在您的所有模型都可添加标签了,那就可开始在应用程序中使用标签信息吧。鉴于现在您仍未编写任何控制器,可以使用方便的 script/console 来测试可添加标签的新模型。要启动控制台,执行: $ script/console创建一个艺术家、唱片和歌曲: >> a = Artist.new( :name => "Bob Dylan" ) => #<Artist:0x35589dc @new_record=true, @attributes={"created_on"=>nil, "name"=>"Bob Dylan", "updated_on"=>nil}> >> a.save => true >> alb = Album.new( :release_name => "Good As I Been To You", ?> :artist => a, ?> :year => 1992 ) => #<Album:0x3500ef8 @new_record=true, @attributes={"created_on"=>nil, "artist_id"=>10001, "updated_on"=>nil, "year"=>1992, "release_name"=>"Good As I Been To You"}, @artist=#< Artist:0x35589dc @new_record=false, @new_record_before_save=true, @attributes={"created_on"=>Sun Feb 18 22:46:32 PST 2007, "name"=>"Bob Dylan", "updated_on"=>Sun Feb 18 22:46:32 PST 2007, "id"=>10001}, @errors=#<ActiveRecord::Errors:0x35573fc @base=#<Artist:0x35589dc ...>, @errors={}>>> >> alb.save => true >> s = Song.new( :title => "Froggie Went A-Courtin'", ?> :length => 386, ?> :track_number => 13, ?> :album => alb ) => #<Song:0x34450f4 @new_record=true, @album=#<Album:0x3500ef8 @new_record=false, @new_record_before_save=true, @attributes={"created_on"=>Sun Feb 18 22:50:47 PST 2007, "artist_id"= 10001, "updated_on"=>Sun Feb 18 22:50:47 PST 2007, "id"=>10000, "year"=>1992, "release_name"=>"Good As I Been To You"}, @errors=#<ActiveRecord::Errors:0x34f65d4 @base=#<Album:0x3500ef8 ...>, @errors={}>, @artist=#<Artist:0x35589dc @new_record=false, @new_record_before_save=true, @attributes={"created_on"=>Sun Feb 18 22:46:32 PST 2007, "name"=>"Bob Dylan", "updated_on"=>Sun Feb 18 22:46:32 PST 2007, "id"=>10001}, @errors=#<ActiveRecord::Errors:0x35573fc @base=#< Artist:0x35589dc ...>, @errors={}>>>, @attributes={"created_on"=>nil, "track_number"=>13, "title"= "Froggie Went A-Courtin'", "updated_on"=>nil, "album_id"=>10000, "length"=>386}> >> s.save => true 接着,创建一些标签。记住,插件为您定义 Tag 模型,因此您可以像定义其他模型那样创建标签: >> t1 = Tag.new( :name => "male vocalist" ) => #<Tag:0x3361700 @new_record=true, @attributes={"name"=>"male vocalist"}> >> t1.save => true >> t2 = Tag.new( :name => "children's songs" ) => #<Tag:0x333a150 @new_record=true, @attributes={"name"=>"children's songs"}> >> t2.save => true最后,将这些标签与一个模型关联,例如,一首歌曲: >> s.tags << t1 => [#<Tag:0x3361700 @new_record=false, @new_record_before_save=true, @attributes={"name"=>"male vocalist", "id"=>10000}, @errors=#<ActiveRecord::Errors:0x335133c @base=#<Tag:0x3361700 ...>, @errors={}>>] >> s.tags << t2 => [#<Tag:0x3361700 @new_record=false, @new_record_before_save=true, @attributes={"name"=>"male vocalist", "id"=>10000}, @errors=#<ActiveRecord::Errors:0x335133c @base=#<Tag:0x3361700 ...>, @errors={}>>, #<Tag:0x333a150 @new_record=false, @new_record_before_save=true, @attributes={"name"=>"children's songs", "id"=>10001}, @errors=#<ActiveRecord::Errors:0x33376e4 @base=#<Tag:0x333a150 ...>, @errors={}>>] >> s.tags.count => 2 当您添加 acts_as_taggable helper 时,就将 << 方法(记住,Ruby 中调用对象的任何东西都是方法,包括 <<)添加到 Artist 模型了。记住,它通过为模型添加 :has_many :tags helper 添加附加运算符(方法!)。这样,您就给“Bob Dylan”艺术家对象添加了两个标签。 >> a.tags => [#<Tag:0x3361700 @new_record=false, @new_record_before_save=true, @attributes={"name"=>"male vocalist", "id"=>10000}, @errors=#<ActiveRecord::Errors:0x335133c @base=#<Tag:0x3361700 ...>, @errors={}>>, #<Tag:0x333a150 @new_record=false, @new_record_before_save=true, @attributes={"name"=>"children's songs", "id"=>10001}, @errors=#<ActiveRecord::Errors:0x33376e4 @base=#<Tag:0x333a150 ...>, @errors={}>>] >> a.tags.count => 2添加了为数据制作标签的功能,您就能利用应用程序完成许多事情了!花点时间浏览 Rails API 文档,熟悉关联方法为您的模型添加的所有方法。它们现在也使用您的标签了! 但还可以更好。acts_as_taggable_on_steroids 插件添加了多个方便的方法供您使用,从而让开发工作更简单、更快速。设计这个插件旨在复制由原先的 acts_as_taggable 插件提供的功能。这意味着您能进行以下操作: >> a2 = Artist.new( :name => "The Flaming Lips" ) => #<Artist:0x326d600 @new_record=true, @attributes={"created_on"=>nil, "name"=>"The Flaming Lips", "updated_on"=>nil}> >> a2.save => true >> a2.tag_list = "alternative, male vocalist" => "alternative, male vocalist" >> a2.save => true >> a2.tags.count => 2注意返回的两个艺术家对象 Bob Dylan 和 The Flaming Lips。用同样的方法添加您选择的四个、五个或更多艺术家,确保为它们做作标签。试着多次使用同样的标签,这样我们下面要用的标签群示例才有意义。
预测对标签群的调用在大多数社会应用程序和基于大众分类法的应用程序中,显示标签数据最常用的方法之一就是标签群。您已经在站点如 Flickr 和 del.icio.us 上看到过这些了。标签群基本上是对某系统中标签的直观表示,其大小依据流行度(也即频率)决定。acts_as_taggable 插件提供了一个计算标签频率的名为 tag_counts 的简便方法。不过,插件的开发人员肯定对 MySQL 有偏见,因为 tag_counts 方法的定义包含了一个 find_by_sql 调用,它使用了带有聚合函数的无效 SQL。依据标准,Oracle 要求非聚合语句必须包含在 GROUP BY 子句中。因此,即使 Oracle 运行正常,tag_counts 也会中断。 不过,希望还是有的;您只需将下面内容添加到 RAILS_ROOT/vendor/plugins/act_as_taggable_on_steroids 插件中的 init.rb 文件的末尾: require File.dirname(__FILE__) + '/lib/acts_as_taggable_override'然后,在 RAILS_ROOT/vendor/plugins/acts_as_taggable_on_steroids/lib 创建一个名为 acts_as_taggable_override.rb 的文件,将如下代码放进去: module ActiveRecord module Acts #:nodoc: module Taggable #:nodoc: module SingletonMethods def tag_counts(options = {}) logger.debug{"Using overriden tag_counts method"} options.assert_valid_keys :start_at, :end_at, :conditions, :at_least, :at_most, :order start_at = sanitize_sql(['taggings.created_at >= ?', options[:start_at]]) if options[:start_at] end_at = sanitize_sql(['taggings.created_at <= ?', options[:end_at]]) if options[:end_at] options[:conditions] = sanitize_sql(options[:conditions]) if options[:conditions] conditions = [options[:conditions], start_at, end_at].compact.join(' and ') at_least = sanitize_sql(['count(*) >= ?', options[:at_least]]) if options[:at_least] at_most = sanitize_sql(['count(*) <= ?', options[:at_most]]) if options[:at_most] having = [at_least, at_most].compact.join(' and ') order = "order by #{options[:order]}" if options[:order] limit = sanitize_sql(['limit ?', options[:limit]]) if options[:limit] Tag.find_by_sql <<-END select tags.id, tags.name, count(*) as count from tags left outer join taggings on tags.id = taggings.tag_id left outer join #{table_name} on #{table_name}.id = taggings.taggable_id where taggings.taggable_type = '#{name}' #{"and #{conditions}" unless conditions.blank?} group by tags.id, tags.name having count(*) > 0 #{"and #{having}" unless having.blank?} #{order} END end end end end end这些代码会覆盖现有的 tag_counts 方法并解决几个问题:首先,它将 #{name} 两侧的引号改成单引号,这样 Oracle 把它当做一个文字,避免了 ORA-00904:无效标识符错误。其次,它给 GROUP BY 子句添加了缺少的语句,从而使 SQL 有效。它还修改了 :start_at 和 :end_at 选项附近的代码,并删除了 :limit 选项。重启控制台或应用程序将确保更改生效,方法可以成功返回调用: >> Artist.tag_counts => [#<Tag:0x34495b4 @attributes={"name"=>"male vocalist", "id"=>10000, "count"=>2.0}>, #<Tag:0x3449578 @attributes={"name"=>"children's songs", "id"=>10001, "count"=>1.0}>, #<Tag:0x344953c @attributes={"name"=>"alternative", "id"=>10002, "count"=>1.0}>]希望将来的版本可以修复该错误。但在修复之前,当您更新了插件时,不要忘记重新应用这些更改。 tag_counts 方法还可以添加条件,如 :start_at、:end_at、:at_least、:at_most 和 :order。它们让您可以进行如下查询: Artist.tag_counts(:start_at => 7.days.ago) # retrieves tags for added in the last 7 days Artist.tag_counts(:at_least => 10) # retrieves tags that have been used 10 or more times. Artist.tag_counts(:order => "name") # order the array of tags by name alphabetically既然有了可以使用的 tag_counts 方法,那就可以利用它生成标签群了。但在开始之前,先要使用 Rails 生成器脚本创建必要的文件。Rails 包含一个名为 scaffold 的生成器,它能提供对给定模型进行基本 CRUD 操作所需的所有文件。您需要给生成器传送您要结构化的模型的名称以及要使用的控制器的名称。接着,对艺术家模型和目录控制器运行 scaffold 生成器: $ script/generate scaffold Artist Catalog所需的文件就产生了。启动内置服务器,查看创建的内容: $ script/server转到 http://localhost:3000/catalog,您将看到今后要使用的列表视图。 为了让我们整个应用程序都可以使用您的标签群方法,需要将以下代码添加到 RAILS_ROOT/app/helpers/application_helper.rb 文件中。您也可以将其添加到 catalog_helper.rb 文件中,但是有可能您也要在目录控制器之外使用 tag_cloud。 def tag_cloud(tag_counts) ceiling = Math.log(tag_counts.max { |a,b| a.count <=> b.count }.count) floor = Math.log(tag_counts.min { |a,b| a.count <=> b.count }.count) range = ceiling - floor tag_counts.each do |tag| count = tag.count size = (((Math.log(count) - floor)/range)*66)+33 yield tag, size end end可能您注意到了在这个列表中有几个对 Math.log 的调用。该标签群方法试图偿“long tail/power law”现象,使用对数分布来对抗势曲线,平衡字体大小的分布。如果没有这些操作,您最后可能只会得到几个大标签和成百上千的小标签。实际上,对数分布放大了许多低流行度标签之间的差异。 接着,添加您的 CSS。使用 scaffold 命令生成基本视图,将其添加到 RAILS_ROOT/public/stylesheets 下的 scaffold.css 文件中: .tagCloud { margin:10px; font-size:40px; } .tagCloud li { display:inline; }该样式设置了标签群的最大字体大小。如果您回头查看 tag_cloud 的方法定义,就会发现:size = (((Math.log(count) - floor)/range)*66)+33。它设置最小字体大小百分比为 33%,并将加权的大小和最小值相加,产生的是您在 tagCloud CSS 类中设置的字体大小的最高频度的标签(最接近 100%)和最低频度的标签(最接近 33%)。与大多数其他标签群算法相比,这个算法的好处是它允许标签的大小有更多的变化。也就是说,它对基于大小的(而不是基于颜色的)标签群最适用。(我把后者叫做“热图”)。 最后,既然底层代码已经就位,就可以添加在视图中显示标签群的代码了。同样的,因为您使用的是 script/generate scaffold 命令,所以已经为您创建好了必要的视图和控制器动作。现在我们将标签群添加到列表动作和视图。首先,将 RAILS_ROOT/app/controllers/catalog_controller.rb 中的 Catalog_Controller 的列表动作更改为: def list @artists = Artist.find(:all) @artist_tag_count = Artist.tag_counts() end您已经将 scaffold 为您添加的分页取消了,这么做只是为了简化。此外,您还为 tag_counts() 方法添加了一个调用,这样视图就能访问到标签频度信息。记住,Rails 中的视图能访问控制器中的任何实例变量。 现在控制器有了创建标签群所需的数据,就剩处理视图了。打开在 RAILS_ROOT/app/views/catalog/list.rhtml 列表动作的缺省视图。list.rhtml 和目录控制器由 scaffold 命令自动生成。将以下内容添加到 list.rhtml 文件的末尾(最后一行的后面): <br <//> &ol class="tagCloud"> <% tag_cloud(@artist_tag_count.sort_by {|t| t.name}) do |tag, size| %> <li><%= link_to h("#{tag.name}"), { :action => "show_tag/#{tag.name}" }, { :style => "font-size:#{size}%"}%></li> <% end %> </ol>接着删除 scaffold 命令放在视图中的分页链接。删除这些行知道末尾;不然会产生异常,因为 @artist_pages 在列表动作中不存在: <%= link_to 'Previous page', { :page => @artist_pages.current.previous } if @artist_pages.current.previous %> <%= link_to 'Next page', { :page => @artist_pages.current.next } if @artist_pages.current.next %> 最后添加 show_tag 动作,它链接到标签群中您的标签。将这个最后的动作添加到 RAILS_ROOT/app/controllers/catalog_controller.rb 文件的末尾: def show_tag @artists = Artist.find_tagged_with(params[:id]) @artist_tag_count = Artist.tag_counts() render :template => "catalog/list" end您不必为该动作创建视图,只需与列表动作使用同一个视图。唯一的区别是,在该视图中的 link_to 调用中您将 tag.name 做为一个参数传递,这样就能保证仅显示您点击的标签。show_tag 动作会在 Artist.find_tagged_with(params[:id]) 方法调用中使用 tag.name 参数。很简单。 最后,您的 list.rhtml 文件应该如下所示: <h1>Listing artists</h1> <table> <tr> <% for column in Artist.content_columns %> <th><%= column.human_name %></th> <% end %> </tr> <% for artist in @artists %> <tr> <% for column in Artist.content_columns %> <td><%=h artist.send(column.name) %></td> <% end %> <td><%= link_to 'Show', :action => 'show', :id => artist %></td> <td><%= link_to 'Edit', :action => 'edit', :id => artist %></td> <td><%= link_to 'Destroy', { :action => 'destroy', :id => artist }, :confirm => 'Are you sure?', :method => :post %></td> </tr> <% end %> </table> <br <//> <%= link_to 'New artist', :action => 'new' %> <br <//> <ol class="tagCloud"> <% tag_cloud(@artist_tag_count.sort_by {|t| t.name}) do |tag, size| %> <li><%= link_to h("#{tag.name}"), { :action => "show_tag/#{tag.name}" }, { :style => "font-size:#{size}%"}%></li> <% end %> </ol>您的 catalog_controller.rb 应该如下所示: class CatalogController < ApplicationController def index list render :action => 'list' end # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html) verify :method => :post, :only => [ :destroy, :create, :update ], :redirect_to => { :action => :list } def list @artists = Artist.find(:all) @artist_tag_count = Artist.tag_counts() end def show @artist = Artist.find(params[:id]) end def new @artist = Artist.new end def create @artist = Artist.new(params[:artist]) if @artist.save flash[:notice] = 'Artist was successfully created.' redirect_to :action => 'list' else render :action => 'new' end end def edit @artist = Artist.find(params[:id]) end def update @artist = Artist.find(params[:id]) if @artist.update_attributes(params[:artist]) flash[:notice] = 'Artist was successfully updated.' redirect_to :action => 'show', :id => @artist else render :action => 'edit' end end def destroy Artist.find(params[:id]).destroy redirect_to :action => 'list' end def show_tag @artists = Artist.find_tagged_with(params[:id]) @artist_tag_count = Artist.tag_counts() render :template => "catalog/list" end end 现在转到 http://localhost:3000/catalog/list 就能看到具有 CRUD 功能的 Artists 列表,下面还有一个标签群: 点击标签将显示一个按标签归类的、已过滤的艺术家列表,下面是相同的标签群。 这仅仅是标签带给您应用程序体验的一个例子。标签群能用非常简单的格式表达丰富的意思 - 它是强大用户界面的标志。 好好利用它正如您所看到的,acts_as_taggable_on_steroids 还存在许多缺陷。从本文完成起,has_many_polymorphs 插件已经开始被接受,成为 acts_as_taggable 插件更强大的替代物。和许多灵活和强大的解决方案一样,它比我们在本文介绍的插件更抽象。此插件并不是一个添加标签的现成的、直接的解决方案,但是它确实出色地解决了 acts_as_taggable_on_steroids 插件的许多内在问题 - 其中包括潜在的模型定义冲突,因没有不灵活的标签分隔符而与 Oracle 不相容,不过最重要的也许是无法对给定标签跨模型查询。 总之,acts_as_taggable_on_steriods 插件是 Rails 应用程序的一个非常强大、易用的扩展。 Matt Kern 多年来一直致力于寻求和开发通过技术(如 Rail)让生活简单化的方法,主要是试图寻求有更多的时间来与家人游览俄勒冈州中部山峰的方法。他是 Artisan Technologies Inc. 的创始人,并且是 Atlanta PHP 的共同创始人。 |