Messenger:Mac with Safari 4

更新了 safari 4 以后 microsoft messenger:mac 出现一个奇怪的问题,每次发送一条消息以后,输入框都会失去焦点,就是说没办法连续输入第二条消息,只能tab一下或者是点击一下。很 suck 的 bug!

在 apple 和 microsft mac 论坛都查了一下,都是更新 safari 4 以后引起的,还不确定是因为 webkit 的关系,还是 security update 的关系。回到 safari 3.2 可以解决问题,但是,谁舍得?作为一个优秀的浏览器,即使是 beta 版本也给所有 mac 用户带来震撼的体验,我想没什么人会舍得降级。

那么,就等待 ms 或者 apple 发布 bug fix 补丁吧,相当的无奈 :-(

扩展 Paperclip

Paperclip 是 Rails 的一个处理 attachment 的插件,相对于以往的 FileColumn 在灵活性和效率上更胜一筹,而且代码也比较好看。这个视频 简单的介绍了 Paperclip 的使用方法。

默认的设置,URL 的占位符中与模型本身相关的只有 id,但是一些情况下,你可能会更希望以其他形式来组织你的附件目录 - 比如以 SKU 来代替数据库记录的 id。这里我们暂不讨论这种做法的好坏,双方面的,好处是目录结构更具有维护性,坏处是万一以后升级数据库,SKU 加个前缀什么的……

Here we go!

使用 paperclip 需要在 model 中调用 has_attached_file 方法,检查文档,有一些简单的使用样例,但是没有我们需要的。通过方法描述我们知道这个方法建立了一个 Paperclip::Attachment 对象,我们继续看文档。对象的方法很少,首先思考:应为我们需要配置的是 attachment 的 url 规则,那么应当是对应整个类而不是单个实例,因此我们只关注 Peperclip::Attachment 的类方法,只有两个。default_options 没有描述,而且展开代码发现并不是我们需要的。

Paperclip::Attchment.interpolation

A hash of procs that are run during the interpolation of a path or
url. A variable of the format :name will be replaced with the return
value of the proc named “:name”. Each lambda takes the attachment and
the current style as arguments. This hash can be added to with your own
proc if necessary.

这正是我们需要的,接下来的扩展就非常方便了:

# app/models/product.rb  

class Product < ActiveRecord::Base  
  has_attached_file :photo,  
    :style => { :thumb => '64x64>' },  
    :url => '/images/products/:to_param.:extension'  
    
  def to_param  
    return self.sku  
  end  
end  
  
# config/initializers/paperclip.rb  

Paperclip::Attachment.interpolations.merge!(  
  :to_param => lambda { |attachment, style| attachment.instance.to_param }  
)

在这里不直接使用 :sku 作为占位符而使用 :to_param 是为了在其他模型中更加的灵活。

终于搞定了这个 blog!

周末的时候买下自己的域名 hozaka.com,再赖上 Weston 的空间,终于可以给自己的 blog 安个家。

WordPress 的安装出乎意料的简单,界面也很友好,先赞一个。默认的模板比较水,可以在 http://wordpress.org/extend/themes 找到很多精美的设计。只不过对我来说,这些模板的代码是在是很糟糕……

在小破 PowerBook G4 上配置好 apache+php,开始动手 redesign,无奈我是 PHP 菜鸟级人物,只能凭经验和语感去写代码,不过似乎运气不错,没怎么见到 php 的 500 页面,哈哈 :)

折腾了半天,终于把几个页面都做好了,马上上传,本来还想导入以前的博客来着,不过 blogbus 的 rss 系统不是怎么友好,还没办法得到所有的 feeds。

庆祝庆祝!谢谢 CCTV,谢谢 Channel[V],谢谢 Weston

ActionView 的魔术:ERB & Binding

Rails 作为一个 MVC 框架,其核心包括三个模块:ActiveRecord,ActionController 和 ActionView。今天这篇博文的主角是 ActionView,解开模板系统的魔术。通常情況下,通过 scaffold 已经能够建立简单的、包含 CRUD 基本功能的页面,完全不需要手动修改 view 的代码。即使不使用 scaffold ,Rails 也提供了众多的辅助方法,创造一个功能丰富的动态页面简直是易如反掌。但是,会用不代表深入理解,最近有朋友问我这些问题:

  1. 为什么编辑一个对象需要在 Controller 创造一个实例变量
  2. View 通过什么方式访问这些实例变量的
  3. 那么多表单辅助方法,都是需要提供 object_name, method 两个参数,怎么就变成实例变量的值了

相信大部分的 Rails 程序员手边的书都是《Agile Web Development with Rails》,书中提到这一点的时候一笔带过,只是说 Rails 在这里用了一个小魔术。这里,我们就来揭开这个魔术吧!

Part 1. Template Files - 模板文件

当一个 action 需要返回一段 html 片段的时候,我们需要建立一个模板文件。根据不同的版本、请求类型,模板文件的文件名也各不相同,从早期版本的 action_name.rhtml ,到现在的 action_name.text.html.erb ,以及扩展的 rjs,在扩展名中都包含了一个关键字:r / erb。它就是 Rails 模板系统的关键:ERb。

Part 2. ERb - Ruby Templating

ERb - 嵌入式 Ruby,是 Ruby 语言提供的一个基本扩展。它支持在字符串中嵌入 ruby 代码片段。看上去似乎很神秘,其实我们每天都用到,下面这种形式一定不陌生吧?

<h1><%= @user.name %></h1>

没错,正是因为 ERb 的存在,使得模板中可以动态地引用对象的属性。

Part 3. Instance Variables of Ruby - Ruby 的实例变量

让我们回顾一下 Ruby 语言的基本要素之一:实例变量。通常我们通过 @time = Time.now 的形式创造一个实例变量。这里我们不重新解释对于“实例变量”的定义,但是必须牢记一点,正如字面所见,实例变量的作用域是当前实例内,也就是说, 只有在实例的内部,才可以直接对实例变量进行读写操作(扩展的访问子方法等等不在讨论范围之内)。那么,为什么 Rails Controller 里创建的实例变量能够在 View 里面访问呢,不是自相矛盾吗?

Ruby 作为一种动态语言,因为其“开放”的特点,使很多原本不可能的编程模式变为可能。比如,通过 Open Class 的特性,你可以动态的为对象注入新的方法定义,或者改写方法的逻辑,或者,通过不同的方法可以在对象的外部访问对象的内部的实例变量。经常使用 console 的朋友可能会了解其中的一种方式:Object#instance_variable_get / Object#instance_variable_set 方法。举个简单的例子:

class User
  def initialize( name )
    @name = name
  end
end

user = User.new( "Jack" )
user.name #=> raise NoMethodError

user.instance_variable_get('@name') #=> "Jack"

user.instance_variable_set('@name', 'Tom')
user.instance_variable_get('@name') #=> "Tom"

可以看到,在没有任何访问子的情况下,我们用这种方式对一个实例变量进行读写操作。

除了这种简单的方式,还有另外一种进阶的方式,也是 ERb 常用的一种方式:Binding

Part 4. Binding

Binding 是 Ruby 语言的自身的一个特性,在任何对象内,self.binding 方法都会返回一个当前对象关联的 binding 实例。不精确的说,binding 对象可以理解成为当前对象的完整的上下文环境。文档中已经包含了一些示例代码,帮助大家理解 binding 对象的作用。最重要的一点是:既然是当前对象的完整上下文环境,自然就包括了对象的实例变量。

那么 Binding 在 ERb 中扮演一个什么样的角色?是一个运行环境的提供者。

回到我们最初的问题,Rails 在 ActionView 中使用了什么样的魔法?答案就是 ERb 和 Binding。首先,获得当前实例的 binding,自然,binding 内也包括了实例变量;紧接着,ERb 允许将模板的内容动态地,绑定到另一个环境中运行。我们依然用刚才的 User 的例子来说明这一点:

# A simple template string

template = "Hello, <%= @user.name %>"
@user = User.new( "Jack" )

# Get binding

binder = self.send( :binding ) # calling a private method


# Rendering template

puts ERB.new( template ).result( binder )
#=> "Helo, Jack"

虽然例子不是非常恰当,但是足以展示 Binding 和 ERB 的用法。我们可以看到,ERB#result 方法将模板字符串绑定在另外一个环境中运行,而这个环境包含了我们创建的 @user 实例变量,因此,模板中的 @user.name 得到了正确的值。

这就是 ERB 的真面目,也是为什么在 ActionView 中能够访问到 Controller 里实例变量的原因。感叹一下动态语言的强大吧!以上只是非常粗糙的讲述ERB的使用,Rails 所做的魔法远不止如此,如果有兴趣,可以查看 Rails 源代码,对于深入学习 Rails 框架也有很大的好处。

最后,补充一下 ERB 的应用场景。虽然在普通的需求中,ActionView 所做的已经足够,但是某些情况还是需要创造独立的模板系统。比如某个场景,客户要求提供一个完全自定义的模板系统,这个时候 ERB 就大显身手了。只需要将数据源载入实例变量中,并且在使用手册里列出可以访问的方法,即使完全不懂 Ruby 语言也可以写出使用这套简单的模板系统了。

Think & Express / 思考与表达

炎炎夏日,在车站等车实在不是一件美差,百无聊赖,只能一边等车,一边观察身边的人群。

这次观察的对象是一个中年妇女,正在打电话。根据通话的内容来判断,应该是对徐汇区的道路不是很熟悉,打电话给他丈夫问路。尽管听别人打电话不是很文明的行为,但是既然当事人不避讳什么,在车站扯开嗓门,也不设计敏感话题,我也没什么必要觉得自己是个坏叔叔 :)

好了,闲扯这么多,还是来看看她通话的内容吧。(经过整理)


  1. “去xxxx到底怎么走啊?”

  • “我就在上次我们去的那条路上”
  • “旁边?车站啊”
  • “732,931,205……”(在抬头看着站牌)
  • “哦,对了,旁边还有个工商银行”
  • 这个场景发生的地点是在我家楼下的公共汽车站。很显然这个妇女没有得到她想要的答案,而她丈夫也没有搞清楚她现在到底在哪里。听着这种对话我不仅哑然失笑。为什么她的思考与表达能力如此之差呢?相信全世界没有人能根据她的这些描述知道她到底在哪里。我们来一句一句的分析:

    2. 上次去的那条路,抛开人的记忆力不谈,即使是按照同一条路线,如果你是在公共汽车站等车的话,怎么也不可能一条马路笔直走吧?那么上次那条路到底是哪条?要知道,条条大路通罗马 3. 回答你在车站旁边并不能给对方的判断带来任何帮助。不过如果你回答在马路上,可能会有冷笑话的效果 4. 如果你仔细得看一下你报的车,会发现他们在徐家汇这一块几乎每个站都是一起的,谁知道你在哪一站?但是同样的,你仔细看看站牌,应该能看到这一站叫什么名字 5. 上海的工商银行遍地开花,除非你在另一个空间

    唠叨了这么多废话,还是没有提供对方一些有用的信息。最简单的,刚才提到的站牌,每个公交站都有名字,路线+站名在全市是唯一的;其次,在刚才提到的工商银 行对面是一所医院,医院的名字自然也是唯一的;再其次,头顶上有一块牌子,清清楚楚的写着这是xx路和xx路交叉口,这也是全市唯一的。

    身边有着如此之多可以作为唯一地点标识的信息,却还是无头苍蝇一般逮到啥说啥。唏哩哗啦说了半天,倒不如花一分钟时间仔细观察一下再打电话,相信就能得到一点指点了。

    有时候,难的是在遇到问题,还能保持一定清醒的头脑来分析问题,解决问题。人类的思考能力,是建立在理性的基础上的。