为Oracle和Ruby on Rails添加标签(三)

日期: 2007-12-04 作者:Matt Kern 来源:TechTarget中国

  这些代码会覆盖现有的 tag_counts 方法并解决几个问题:首先,它将 #{name} 两侧的引号改成单引号,这样 Oracle 把它当做一个文字,避免了 ORA-00904:无效标识符错误。其次,它给 GROUP BY 子句添加了缺少的语句,从而使 SQL 有效。它还修改了 :start_at 和 :end_at 选项附近的代码,并删除了 :limit 选项。重启控制台或应用程序将确保更改生效,方法可以成功返回调用:  

>> Artist.tag_counts
  => [#"male vocalist", "id"=>10000,
  "count"=>2.0}>, #"children’s songs",
  "id"=>10001, "count"=>1.0}>, #"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 应用程序的一个非常强大、易用的扩展。

 

我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。

我原创,你原创,我们的内容世界才会更加精彩!

【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】

微信公众号

TechTarget微信公众号二维码

TechTarget

官方微博

TechTarget中国官方微博二维码

TechTarget中国

相关推荐