Today's the day

向软件大牛炫耀我会焊单片机,向硬件大牛炫耀我会写 Rails,向软硬件大牛炫耀我生物,向软硬件生物大牛炫耀我会折腾期货 -_-bbb

修改下 In Place Editing 插件

In Place Editing 这个插件代码非常简洁,却方便的实现了即时编辑的效果,不过自从从 Rails 的核心移出去之后,貌似就没有再升级过。

首先它不支持 Validate,In Place Editing 的保存不经过检查,即使你 validates_presence_of :name,也可以在 In Place Editing 中把 name 清空并保存,而且这样做了之后,由于 name 没有了文字,也没法点击编辑了。

另外它也不支持 protect_from_forgery。

虽说有个 REST In Place 插件,似乎是 In Place Editing 的替代品,其实稍微修改一下,In Place Editing 就能重放光芒了~

没法 validate 的缘故是因为它用了 update_attribute 的方法更新属性,只要改成 update_attributes 就可以了,然后检查保存是否成功,如果失败,将错误信息显示出来:

lib/in_place_editing.rb:

  1.     def in_place_edit_for(object, attribute, options = {})
  2.       define_method("set_#{object}_#{attribute}") do
  3.         @item = object.to_s.camelize.constantize.find(params[:id])
  4.         if @item.update_attributes({attribute.to_sym => params[:value]})
  5.             render :text => @item.send(attribute).to_s
  6.         else
  7.             render :text => @item.errors.on(attribute.to_sym)
  8.         end
  9.       end
  10.     end

也可以加个样式着重下错误信息:

  1. render :text => "<span style='color:red;'>#{@item.errors.on(attribute.to_sym)}</span>"

protect_from_forgery 的问题只要加上 authenticity_token 参数就可以了:

lib/in_place_macros_helper.rb:

  1.   def in_place_editor_field(...)
  2.     ...
  3.     in_place_editor_options[:url] = in_place_editor_options[:url] || url_for({ :action => "set_#{object}_#{method}", :authenticity_token => form_authenticity_token, :id => tag.object.id })
  4.     ...
  5.   end

 这样就 OK 了,效果还不错:

 

respond_to 新构想

respond_to 非常好用,可以根据不同的 format 来选择不同的应答策略,并且自动设置相应的 MIME 值,看上去也非常爽目。

在 Blog 系统中,比如文章的 RSS,就可以:

  1. def index
  2.    @posts = Post.find(:all)
  3.    respond_to do |format|
  4.        format.html { ...}
  5.        format.rss {...}
  6.    end
  7. end

这样比在单独构建一个 RSS action 要好得多~

不过,如果 Blog 通过 html 显示出来的话,还需要做其他一些事情,比如构建 Blog 的各个边栏,这些事情一般都放在 before_filter 中去做:

  1. class PostsController < ApplicationController
  2.     before_filter :get_sidebars
  3.     ...

但是这些工作在 RSS 中完全不需要,那么怎么在 RSS 忽略掉这些工作呢?

一个选择就是去掉 before_filter,把 get_sidebars 写入到 format.html { } 中去,这样的话,PostsController 里面每个 action 的 format.html 都要这样做,不是啥好办法。

第二个选择就是在 get_sidebars 里面检测 format:

  1. def get_sidebars
  2.     if params[:format] == "html"
  3.        ...create sidebars

这样似乎还算 ok,其他的方法还没有想出来……

前两天,正好看到 maiha 写的新 respond_to 表示方法的构想,去掉 respond_to 那个 block,而按照 aciton.format 的格式,把不同 format 的处理,放到单独的函数中去:

  1. def index
  2.     @posts = Post.find(:all)
  3. end
  4.  
  5. def index.html
  6.     ...
  7. end
  8.  
  9. def index.rss
  10.    ...
  11. end

这样看上去比 respond_to 清晰了很多,如果可以实现,那么如果在 before_filter 里面也可以:

  1. before_filter :get_sidebars, :only => "*.html"

就能完美的解决上面的问题了~

用 Texvc 生成数学公式

is-Programmer 目前用 l2p 这个小程序,配合 TeX 系统来生成数学公式图片,现在又有新的选择了,那就是 Texvc ~ 

texvc 是 MediaWiki 附带的用来生成公式图片的小程序,在 MediaWiki 安装路径下的 Math 目录中可以找到这个程序,和 l2p 一样,需要配置好 TeX 环境。

genki 写了一个简单的 texvc 的 Ruby wrapper,这样在 ruby 中就可以方便的生成公式图片了~

首先安装,gem 包名称叫做 genki-texvc:

  1. sudo gem install genki-texvc

使用方法非常简单:

  1. require 'texvc'
  2. Texvc.parse( 'f(x)=\int_0^x \sin(t)\,dt' )      #=> Magick::Image

就会生成:

 

parse 之后会返回一个 Magick::Image 实例,你可以显示出来,或者写到文件中,或者再做进一步处理~

 

Ruby 1.8.6 p230 p238 有内存泄漏 Bug

这两天有些奇怪,服务器上 Rails 进程的内存占用总是不断上涨,只要一天时间,内存就暴满,然后开始啃虚拟内存,网站也变得很慢。

开始以为是 ruby-gettext 的问题,因为 1.90  的 ruby-gettext 确实有这么个内存泄漏的 bug,不过我当初打过了补丁,应该不会出现问题。尝试升级到 1.91,问题依旧……

接着怀疑是代码本身的问题,不过前些日子一直正常,这两天又没有改过网站代码,所以排除。

后来想起来,上个星期把服务器上的 ruby 升级为最新的 1.8.6_p230,难道问题出在这里? Google 了一下,果然:

[Ruby 1.8 - Bug #216] (Open) Memory leaks in 1.8.6p230 and p238

看来 production 下不能使用 p230 和 p238 了,即使是 is-Programmer 这样流量很小的网站,问题都很严重。

降级回 1.8.6_p114,问题解决~

像 Lua 那样引用 Hash 元素

Lua 中的 Table 可以拿来当作多种数据格式来使用,比如 Hash ( Dictionary ):

  1. h = {a=1,b=2,c=3}
  2. print(h['a'])
  3. 1

最爽的是,可以用 h.a 这种形式来引用 Hash 中的元素:

  1. print(h.a)
  2. 1

 利用 Ruby 的 method_missing,也可以这样爽一把,仅仅需要:

  1. class Hash
  2.     def method_missing(method, *args)
  3.         self[method]
  4.     end
  5. end

即可,测试:

  1. h = {:a => 1, :b => 2, :c => 3}
  2. puts h.a
  3. 1

只要 hash 的 key 不要与 Hash 内置的方法重名就可以了~ 

啥?还要实现赋值? 这个好办,只要将上面的代码改为:

  1. class Hash
  2.     def method_missing(method, *args)
  3.         if method.to_s =~ /=$/
  4.             self[method.to_s.chop.to_sym] = *args
  5.         else
  6.             self[method]
  7.         end
  8.     end
  9. end

就可以了,测试:

  1. h = {:a => 1, :b => 2}
  2. h.a = 456
  3. puts h.a
  4. 456

感觉不错~