Ruby 语言 思想驱动生活

September 14, 2007

acts_as_taggable

Filed under: Rails — liubin @ 19:19

这个世界到处都是tag
而且这个世界上好像有两个acts_as_taggable,一个是dhh的plugin版的,一个是gem版的。
比较了半天,发现还是gem版的比较好(http://rubyforge.org/projects/taggable/)。
具体来说
1.gem对于不同的要tag的对象,可以用TagsTable1s格式的表来存tag和对象的关系,比如photo的tag用photos_tags表。
plugin版的则只用一个表taggings,用taggable_type这个字段来表示tag的对象类型。
2.可以为tag关系增加属性。
plugin版的tag关系表只有3个字段(不包括id),要想给这个tag关系加其它属性则比较困难。
gem则容易多了。
gem的tag和被tag对象之间的连接表除了tagid和被tag对象id,还可以有别的属性。
在给对象加tag的时候,可以顺便更新这些属性:

  1. # We can do some interesting things with it now
  2.   person = Person.new
  3.   person.tag "wine beer alcohol", :attributes => { :created_by_id => 1 }
  4.   Person.find_tagged_with(:any => 'wine', :condition => "tags_people.created_by_id = 1 AND tags_people.position = 1")

3.统计功能
tags_count可以统计每个tag被用了多少次

  1. # Gets the top 10 tags for all photos
  2.   Photo.tags_count :limit => 10 # => { 'beer' => 68, 'wine' => 37, 'vodka' => '22', ... }

4.性能可能gem的好一点
plugin版的好像是在给一个对象加tag的时候,会吧这个对象的tag先删掉,再全部加上,性能上有点浪费。

5.容易修改
gem版的写的比较简单,很容以自己进行扩展。
6.gem版的自带一个cloud,可以根据tag的不同显示不同大小的文字。

September 7, 2007

RubyConf 2007 agenda

Filed under: Ruby — liubin @ 8:24

RubyConf 2007
November 2-4, 2007
Charlotte, North Carolina
http://www.rubyconf.org/agenda.html

September 5, 2007

哪有数据库抱怨sql太复杂的

Filed under: 技术 — liubin @ 22:30

其实就是一个简单的update语句

  1. UPDATE TAB1 SET COL1 =
  2. SUBSTRING(COL1 FROM 1 FOR POSITION( "AAAAAA" IN UPSHIFT(COL1))-1) 
  3. || "BBBBBB"||
  4.  SUBSTRING(COL1 FROM 
  5.  POSITION( "AAAAAA" IN UPSHIFT(COL1))  + 7
  6.  FOR CHAR_LENGTH(COL1) - POSITION( "AAAAAA" IN UPSHIFT(COL1)) - 7)
  7.  WHERE POSITION( "AAAAAA" IN UPSHIFT(COL1)) > 0;

这个语句就是想把一个字段的AAAAAA替换成BBBBBB而已,不过sql/mp没有提供replace之类的函数,只好用这样的土方法了。(如果这个字段有5个AAAAAA,则这个语句要执行5次,呵呵,够土)
但是执行的时候出错:
*** ERROR from SQL [-8300]: File system error occurred on
*** \XXXXX.$DATA01.TEST.TAB1.
*** ERROR from File System [1133]: The selection expression or update expression
*** is too complex to be represented in NonStop SQL/MP internal data
*** structures.

哪有数据库抱怨sql太复杂的,只有人脑想不到的,没有机器处理不了的。
如果用select来选这个字段(当然包括那些函数)的话则没问题,所以应该说这些函数的组合应该没问题的,可能是数据类型限制。结果把表定义中这个字段改小一点就好了。试了几次,G06.28的话是1424,如果char列的长度是1425,就会出上面的错误。

September 3, 2007

Rails中使用ESI实现页面cache

Filed under: Rails — liubin @ 17:56

什么是ESI
ESI的全称是Edge Side Includes,是一个基于XML的标记语言,目的是在HTTP中组装各种资源。是由Oracle和Akamai等公司提议的,在W3C的网站也可以找到相关规格说明,最新的是2001年的了,也不是什么新东西。传统的cache技能基本都已页面为单位进行缓存,问题就是页面部分的动态内容可能比较多,而且是每个客户端的内容都不一样(比如个人的登录信息,欢迎xxx等。),缓存比较困难。ESI为了能把页面的一部分进行缓存,使用基于XML的标记语言,来描述对page内个内容的缓存情况。这样,服务器(缓存部分)就可以只缓存共同部分了。
ESI有点类似SSI,但是它比SSI功能更丰富。
目前支持/实现ESI的开源服务器包括Squid,Mongrel-ESI等,商用的有Oracle和Akamai的服务器。

要在Rails里支持ESI需要安装两个插件,一个是Mongrel用的插件Mongrel-ESI,一个是Rails用来处理ESI标记(tag)的fragmentFu。两个软件都可以在http://mongrel-esi.googlecode.com找到。
如何安装一下Mongrel-ESI我就不说了,因为我也没有装过,下面的代码我都没有试验过。
下面来看一下ESI的代码,下面是一个测试的例子(转自http://blog.tkmr.org/tatsuya/show/368-rails-10-esi,日文

  1. cd /home/my/rails/app/path
  2. ----index.html-----
  3. <h1>Welcome ESI!!</h1>
  4. <p><esi:include src="/welcome/now" max-age="45"/></p>

esi标记里的就是ESI的内容了,应该比较好理解,max-age的意思就是页面缓存保留的时间,这里的话每45秒缓存就会被更新一次。

再来看看控制器里的代码:

  1. ./script/generate controller welcome now
  2. ----welcome_controller.rb----
  3. def now
  4.   render :text => "#{Time.now}"
  5. end

启动Mongrel_esi:

  1. mongrel_esi start
  2.   ** Starting Mongrel listening at 0.0.0.0:2000

然后就可以去浏览器里看看了,是不是45秒那个显示的时间才更新一次。

上面的例子是标准的ESI写法,当然Rails中这样写就有点累了,这个时候就需要fragmentFu这个Rails的plugin了。

在ERB里,写法是这样的:

  1. ./script/plugin install http://mongrel-esi.googlecode.com/svn/trunk/plugin/fragment_fu
  2. ----/app/view/welcome/index.html.erb----
  3. <h1>Welcome ESI!!</h1>
  4. <p><%= render :esi => {:action => "now"}, :ttl => 45.seconds %> </p>

ttl这个名字比较亲切。

当然,ESI里面也能使用Cookie或者Http的request数据:

  1. #query string
  2. <p><%= render :esi => "/users/name/$(QUERY_STRING{my_name})" %> </p>
  3. #Cookie
  4. <p><%= render :esi => "/users/home/$(HTTP_COOKIE{UserID})" %> </p>

除此之外,ESI还有异常处理机能。因为ESI指令的include可以指向别的地址,所以,取得cache内容也可能失败。

比如下面的代码(来自http://revolutiononrails.blogspot.com/2007/08/advanced-rails-caching-on-edge.html

  1. <esi:try>
  2.   <esi:attempt>
  3.     <esi:include src="/latest" max-age="5" timeout="1"/>
  4.   </esi:attempt>
  5.   <esi:except>
  6.     <esi:include src="http://static.foo.com/latest" max-age="5" timeout="1"/>
  7.   </esi:except>
  8. </esi:try>

这个也应该比较好理解,如果尝试1秒内取得不到/latest的话,cache服务器就会放弃,而去取静态页面的内容。

另一不错的功能就是Invalidation,就是使已有的cache的内容失效,因为它cache的内容已经被更新过了。在Rails自带的cache功能里需要在action调用失效方法的,或者用sweeper回调。ESI则有invalidate指令:

  1. <esi:invalidate>
  2.   <?xml version="1.0"?>
  3.   <!DOCTYPE INVALIDATION SYSTEM "internal:///WCSinvalidation.dtd">
  4.   <INVALIDATION VERSION="WCS-1.1">
  5.     <OBJECT>
  6.       <BASICSELECTOR URI="/foo/bar/baz"/>
  7.       <ACTION REMOVALTTL="0"/>
  8.     </OBJECT>
  9.   </INVALIDATION>
  10. </esi:invalidate>

参考链接:

http://revolutiononrails.blogspot.com/2007/08/fragmentfu-fun-with-fragments.html
http://revolutiononrails.blogspot.com/2007/08/advanced-rails-caching-on-edge.html
http://www.w3.org/TR/esi-lang
http://blog.tkmr.org/tatsuya/show/368-rails-10-esi

Powered by WordPress