用Rails实现“乐道”构想
“乐道”构想
我总觉得有些优美的歌曲,如果你不去推荐,那么别人可能真的没机会听到。本着这个想法我在2001年建立了“神话年代论坛”,开始推荐自己喜欢的音乐。采用论坛推荐音乐并不是一种很好的形式,它就好比是一个大的集贸市场,每个人都在这里买卖东西,只要你是论坛的注册用户。这种方式在2001年的时候还很原始,无非就是你提供个 mp3 下载,我喊声好,然后下载走人,缺乏交流,也想当的混乱。
2004年我在5dblog 注册了一个博客,起名为“牧羊人之乐”继续我的音乐推荐之旅。当时论坛的混乱是自己无法控制的,那么博客是自己写的,控制起来就相对容易一些。比论坛时期进步一点的是,我为推荐音乐专门编写了两个flash 播放器(一个用于播放音频,一个用于播放视频见图1)。但是两年的播客推荐又让我发现了音乐播客这种形式的缺点:它更像是一个自言自语的场所,就好像是每个人都有很多音乐围绕着它,但是如何与他人之间寻找交集,如何与喜欢同一个音乐的人分享自己的感受就变得很困难。播客推荐的音乐通常是围绕他自身的喜好来定的,而我始终认为音乐推荐不应该“以人为本”,而是“以音乐为本”,把那些喜欢它的人聚合起来。
于是一个关于多人推荐音乐的播客网站的想法就在我脑海形成了,这是“乐道”最初的构思。后来演变为一种“DJ 听众模式”的网站形式,这是一种在现实生活中有近似例子的模式。一些 电台DJ 们有自己的音乐推荐栏目, 比如北京音乐台吕游的《浪漫情歌》,伍洲桐的《零点夜话》志飞《世界歌曲排行榜》, 听众在收听节目的时候可以通过打电话的形式参与,只是这种参与形式比较有限。与之相比, “乐道”的模式要稍微先进一些。但是光靠几个 DJ 很难维持新歌推荐的数量,如何从访客留言中发现“潜在”DJ 就成了乐道急需的另外一个功能,于是我开发了“大众推荐”,接连有四五个新人通过“大众推荐”成为正式注册DJ, 事实上他们的确是那些真正喜欢音乐推荐的人,我自己也从中收益很多,发现了很多自己从来没听到过的好音乐。
“
乐道”
技术
其实我很早就有了关于创建一个音乐推荐网站的想法,但是迟迟因为技术上的问题得不到解决而无法去实现。首先是前台问题,音乐推荐网站不同于普通的论坛、新闻、CMS 系统网站,它首先是个多媒体的平台,也就是说普通的 HTML、 JAVSCRIPT、 AJAX 都是无法满足它的要求,只有采用先进的多媒体网页技术。早期 flash 版本的脚本能力太过简单,直到带有 ActionScript2 的 Flash 7 出台后,这个开发平台才让我投身其中,它对开发人员来说有很多吸引人的地方,第一:Flash 插件的占有率太大,几乎98% 的浏览器都会安装Flash。第二:Flash 7 的 Action Script 2 采用了类似 Java 的面向对象的语法,很适合 Java 程序员学习和使用。第三:Flash 的多媒体创作能力应该是数一数二的,国内用户多把它当作动画工具,而在国外则大量用于交互式网站。
后台技术的选择颇为费时,实际上我从2002 年开始从事 java 网站的开发工作,其中接触了不少的 web 框架,但是始终没有一个框架符合我的要求。 j2ee 包含的规范实在太多,而且每个规范都会有各种实现(包括各种开源实现)方式,如何将这些东西组装为一个全功能的网站开发工具包,如何选取一个合适的框架方案始终困扰着我,直到 rails框架在2005年横空出世,才让我感觉到实现自己想法的时机到了。
为什么选择 Rails ,其实是很自然的事情,Java 程序员选择 ruby ,是因为它更面向对象。 Rails 框架在当时可以说是一枝独秀, 基于
python 的Django 框架的正式版本在当时还没有正式推出(现在也没有),而PHP 的各种框架还在受困于php 自身的问题而极力模仿 Rails,选择Rails 根本是不需要思考的问题。这里值得一提的是,对于那些自己打算创业的人士来说,选择一款 agile 的框架非常重要,对于小公司和个人来说,开发效率对他们来说是至关重要的,从人力、物力和时间上,他们都无法与大公司相提并论,而他们有的就是好的想法,高效快速的开发并实现自己的想法就变得很重要。
“乐道”实践
2005 年4月份我写了一篇《Ruby on rails 实践》的教程后,又因为出差等事情把开发“乐道”的事情搁置下来,直到06年三四月份的时候,我感觉到不能再拖延这个实现想法的时机了,于是我向公司提出辞职,正式开始了采用 rails 开发“乐道”的工作。我当时给自己定的是目标是三个月实现这个网站的雏形。5 月份开始,终于在 7 月底将乐道正式部署到服务器上。
有人会问:“既然 Rails 开发那么容易,为什么开发一个像乐道这样简单网站要花费三个月?实际上真正用在开发上的时间大概是三个多星期,而前期学习各种技术的时间却占据了一个多月,这些学习不仅包括研读那本著名的“Rails Book”,还有开源操作系统和数据库服务器的管理。
在开发“乐道”的过程中,我遇到了一些问题,在这里做一些说明,我想对那些初学者可能有一些启发作用。
1: 数据迁移
在5D博客上推荐音乐时,5Dblog 的网站在初期曾经被黑客攻击造成两次数据丢失。因此我将每次的音乐推荐都按照数字编号保存为文本文件,一是为了备份,二是为了播放器动态加载显示用。为了在Flash 中显示中文,文本文件的编码采用了
utf-8 ,编码方式与现在的后台数据库相同。这个看似不得已的操作为后来移植到新数据库提供了方便。
我选用的数据库是
postgresql ,数据转换程序采用
ruby 来编写,我曾在一个项目中采用
ruby 编写过从sqlserver 迁移到
oracle 数据库的脚本,所以这次将文本文件转移到
postgresql 的工作变的非常容易。Ruby 对
mysql 的支持非常好,有好几个 c binding 的实现,
postgresql 就没那么幸运了,好在通过 DBI 方式可以访问 ODBC 数据库,所以我下载了
postgresql 的 ODBC 驱动,设置了 ODBC 源后开始编写脚本转换程序。所有的推荐文本文件都放在一个
txt 目录下,每个文本文件采用如下格式:
------------------------------------------
&ctx=歌词。。。
&rec=推荐文章。。。
非常经典的老歌曲,达明一派曾经翻唱过,有点恬淡的哀伤
这个版本应该是原唱,也是我听过的最好的版本。
&title=petula clark
-------------------------------------------
&artist=Kiss me goodbye
转换代码如下:
require
'
rubygems
'
require
'
dbi
'
@source_directory
=
"
txt
"
i
=
0
DBI
.
connect
(
'
DBI:ODBC:ledao, ledao, ledao) { | dbh |
Dir.open(@source_directory).each { |file|
next unless ( file =~ /[.]txt$/ )
@source_full_name = "#{@source_directory}/#{file}"
n = "#{file}".gsub!(/.txt/,
''
).split(
'
_
'
)[0]
text = File.open(@source_full_name).read()
fields = text.split(/&.*=/)
@song_txt = fields[1]
@song_rec = fields[2]
@song_title = fields[3]
@song_singer = fields[4]
i += 1
puts "song : [" + file + "]" + @song_title
songsql = "insert into songs (id, category_id, title, artist, swf) VALUES (?, ?, ?, ?, ?,?)"
dbh.prepare(songsql) { |t|
t.execute(i,n,@song_title,@song_singer,file)
}
}
}
具体细节可以参看
enterprise ruby 一书。
2:关于login 和图片上传.
Rails 的wiki 站上提供了很多
login generator, 早期 Rails 的login generator对开发自己的应用来说缺乏实用性。因为大部分
generator 无法满足定制特定系统的要求。但是这些 generator 对于学习开发一个登录系统很有帮助,开发
login 功能我参看了 typo 的实现。对于一个网站的开发来说,我觉得最麻烦的是用户授权与认证,大部分web 框架都不提供内置的支持,对于一个像乐道这样简单的网站来说相对容易一些,因为只有认证用户(DJ)和非认证访客(听众)。但是对于一个完整的 CMS 系统来说,如果框架集成了好的用户管理系统是非常重要的,在这点上 Django 就做的很出色,它的
admin 功能模块跟ORM 集成的很密切,而且还拥有一个全功能的用户组管理系统。据说 Rails 新版本将集成一个admin管理的插件,让我们拭目以待。图片的上传和裁减对于一个论坛或博客来说都很重要,用户需要根据需要上传图片,系统必须对图片做必要的裁减以防止文件大小和尺寸超出限定范围造成大量占用磁盘空间和页面显示超出的现象。Ruby 通过
Rmagick对
ImageMagick 提供了良好的支持,而且代码非常简单, 网上有相应的代码实现可供参考。
3::数字验证码的实现
在开发“乐道”的留言功能的时候,我并没有参看其他的 rails 验证码的实现。因为在开发 Java 项目时,我曾经做过此类工作,所以知道应该如何实现,很多实现采用了GD 库生成数字图片的方式,后来在 railscn 上也发现有人贴出了类似的实现,但是考虑到每次留言生成图片可能会增加后台服务器的负担。所以我采用了一种简单的方式来处理,这种方式在最初实现的时候考虑不周,不过后来逐渐完善起来,实际应用效果还可以。
4: Ajax 的应用
Rails 对
ajax 提供了良好的支持,最初的时候我在三个地方采用了
ajax 。
a) 首页左侧的最新留言最初采用的方式是:每隔一分钟去数据库检索最新10条留言。在访问人数少的时候,性能影响并不大,如果访问人数多了,可以采用延长轮询的时间间隔。但是从实际应用考虑,大部分人停留在首页的时间并不是很长,基本上都是停留不了一会就直接进入单曲收听页面,这种即时更新的功能就沦为一种摆设,没有实际意义。所以后来就去掉了。
b) 首页最上面的查询歌曲和歌手的搜索框,最初提供了随着用户的输入文字自动从数据库中检索匹配的歌曲名并以下拉框的形式加以显示。比如你输入一个“爱”,系统会自动从数据库中检索出“爱的代价”,“让爱自由”,“爱情是蓝色的”,这个ajax 功能效果很好,但是担心会造成服务器性能问题,后来也将它去掉了。最近我再三思索准备重新使用这个功能,因为实际使用中同时大量搜索的情况并不多见。
c) 留言后不刷新页面显示最新留言。这是现在唯一保留的Ajax 应用,而它的确是很需要的一个功能。在最初没有采用 Ajax 实现的时候,每次听众留言后,页面重新刷新造成歌曲播放的中断,这种方式很影响听歌的感觉。采用
ajax 实现后,效果很好,所以功能保留到现在。
5: 关于 Javascript 编辑器
大多数论坛博客的发帖都提供了 javascript 编辑器功能,用户可以通过插入外部图片,flash 连接,改变字体颜色,大小的方式来给帖子“增色”。这种个性化的措施却带来管理上的不便。比如插入外部图片可能会因为断链而显示失败,插入的图片无法控制显示大小,五花八门的字体颜色大小定义会造成网站风格的不统一等等。对于乐道而言还有一个不利之处:在首页的列表视图中,会显示每个推荐文章前30 个字的概要,如果在推荐的开头插入过多的图片,由于这些图片是以
html 文本的形式保存在数据库中,那么按照固定字数裁减造成图片显示不全,并以源码的形式显示出来,而且也无法对文章字数进行精确统计。 另外一个问题是,显示编辑器的速度很慢。在乐道开发初期,我采用了
tinymce ,它是当时我找到的最小巧的javascript编辑器。但是在实际应用中显示速度还是很慢,如果打开的功能很多而且网速较慢的情况下,会看见功能图标一个一个的显示的情况。所以最终根据实际需要,我没有采用Javascript 编辑器的功能。
6: 关于
unicode
乐道网站最初上线的时候出现过字符乱码的问题,开始我想当然的认为
postgresql 数据库中设置为
unicode, 页面编码采用
utf-8,那么显示就应该是正常的,后来发现页面显示虽然正常,但是用浏览器查看
HTML 源码确是乱码。根据网上搜索的相关资料做了如下的修改,问题才得到解决。
在
application.rb 中添加如下代码:
before_filter
:
configure_charsets
normalize_params
:
form
=>
'
KC
'
def configure_charsets
if
request
.
xhr
?
@headers
[
"
Content-Type
"
]
=
"
text/javascript; charset=utf-8
"
else
@headers
[
"
Content-Type
"
]
=
"
text/html; charset=utf-8
"
end
ActiveRecord
::
Base
.
connection
.
execute
'
SET CLIENT_ENCODING TO UNICODE
'
End
Config 目录中的
enviroment.rb 的前面添加
$KCODE = 'u'
require 'jcode'
之后我又增加了一个有趣的功能:鼠标移动到列表页面中推荐文章的概要上,会弹出前五个留言的概要。参看图3:
而在提取留言概要信息的时候,再次出现了乱码问题,继而引发了浏览器报
java script 错误。 后来经过搜索才发现还是因为rails 内置的
'jcode' 的
unicode 支持问题。通过安装
unicode 插件才解决了这个问题。
7: 关于开发编辑器的选择
很多
rails 开发人员受
DHH 的影响而采用 Textmate 编辑器, 但是这款苹果软件对大多数 PC 机用户是可望不可及的。其实熟悉vim 的用户可以使用
rails.vim 得到很好的开发体验,youtube 上还有相关的视频。“乐道”上线后的连线修改时,我就经常采用这种方式。对于
windows 用户来说,pspad 这款内置
ftp 功能的编辑器是一个不错的选择,它有
ruby on rails 语法颜色支持,虽然功能简单,但是开发程序非常好用。内置的ftp 客户端配合服务器上安装的
ftp server ,感觉就像是在编辑本地文件。
关于 Rails
Rails同样存在一些缺点。比如,它没有项目的概念,所有开发都是应用,也就是说任何一个网站都是一个应用,而下面是靠 controller 来控制 action, 它不包含 project 的概念,这样就会造成同属于一个项目的不同应用之间相互共享复用变得很困难。最近我在公司开始采用的 Symfony PHP5 framework 做项目,Symfony 就有 project , application, module 的概念,一个网站通常是一个 project ,下面可以有各种应用application,每个应用又可以有各种模块module(类似于 rails 的 controller)。而 Python 的框架 Django 也有 project 的概念。 Rails 为了让程序员不必再学新的模板语法,所以在视图层采用了和服务端同样的脚本语言 ruby ,这其实是一种重复 JSP 错误的倒退,虽然现在也涌现了不少可替代的 Rails 模板方案,但是 Erb rhtml 始终还是 rails 模板的主流。Rails 有 Component 的概念,在开发乐道中,我就编写了大量的 component , 效果还不错。它的 Component 和 Hivemind 的组件还有很大的差距,对于一个程序员独自开发网站来说,这些技术还不错,至少还在个人掌控中,但是如果是很多程序员和网页制作人员合作建站,就会产生问题。Rails 没有好的封装组件的形式,复用性差,不过新的 plugin 机制可以完全实现功能性组件的要求。从现在发展看,Rails 开发网站的趋势就是将大量基础设施以 plugin 的形式实现,看来早期 Rails 站点的重构也不可避免了,乐道网站初期碰到的中文字符集的问题就是通过插件来解决的。
网站开发的感悟:
1: 做一件事情的热情远比完成它所需要的技术更加重要。如果没有热情,就算是碰到一点小困难,你也会放弃,相反,就算是再大的困难你也能克服。
2:尽量不要到国内的技术论坛去提问,最好的方式是自己从 Google 上搜索。
3:国内程序员之间喜欢谈论技术的人多,真正闷头做事的人太少;各种论坛上相互争吵,辩论的多,写代码的人少。我也曾经是这样的,很多东西都是停留在想法上,开始对 ROR 的顾虑也很多,性能啊,扩展啊。在网上搜索到很多这样的辩论,曾经动摇过我使用 ROR 的决心, 但是最终开发效率这一点占了上风。 其实仔细想想,你如果不喜欢一个东西,会找出很多原因,如果喜欢它,一条理由就足够了。
4、我在开始做网站的时候,界面设计选用了很复杂的模板。来“乐道”网站的人无非是推荐音乐、听音乐、参与评论和搜索,鼓捣花哨概念和技术的想法可能从最开始就是在远离你的用户。
5、Ajax应该限制在某些特定功能的网站上(比如 Gmail、 Google Map),整个网站采用它应该是不合适的,而且浏览器之间兼容性的问题的确还是存在的。ROR 提供了非常简单的 Ajax 使用方式,但是在使用它之前千万要考虑一下,这样做是否会给你的页面带来复杂性和服务器性能上的问题。
6、 ROR是一种技术,众多后台技术中的一种,网站的访问者并不会因为你使用了 R0R 就给你掏钱,甚至是留下个好印象。网站的内容是主要的。技术应该是实现你想法的工具,如果网站成为技术的试验品,对我来说就没有什么意义了。
小结
ROR 的好处在于:如果你有什么想法,你总是能很快的实现,只要你掌握了基本的技术,你就可以发挥你的想象来建设你的网站。ROR 网站开发的灵活性还体现在开发方式上,网站部署成功后,新功能的增加我基本上都是直接连接远程服务器来做的,包括调试。Rails 的动态性表现在最初的development环境中不需要重新启动 web 服务器,你写的 ruby code 直接就可以通过刷新浏览器生效,在 production 环境中,即便重新启动 web server ,也非常的迅速,访客甚至感觉不到重新启动了 web server。这种灵活性使得随时开发部署开发新功能成为可能。