`
seamon
  • 浏览: 21948 次
  • 性别: Icon_minigender_1
  • 来自: 北京
博客专栏
19c4d30c-d52a-3cc5-b233-a4a7d92b5798
rails3项目解析
浏览量:19096
社区版块
存档分类
最新评论

rails3项目解析之2——rails基础

阅读更多
rails3项目解析之1——系统架构
rails3项目解析之3——redis


rails 3.0是2010年8月份发布的。迄今为止,3.0已历经多个tiny版到了3.0.8。3.1已经放出rc4,看起来离正式版已为期不远。相对于2系,3系还是有一些令人惊喜的变化,而且在架构上也规范和严整了许多。3.1中更是又加入了几个颇为有趣的特性。我们的项目一直都是紧跟rails新版,很欣慰能够毫无道德压力地做一个喜新厌旧常换常新的男人。但什么都追新也吃了不少小苦头,不过仍然死不悔改,大家都在坐等3.1发布试吃。

更多关于rails3的新特性,网上一抓一把,需求和欲望比较强烈的同学可自行解决,在此不再赘述。下面主要说一下我们这个项目。因为项目不大,而且第一期没有太多用户互动的内容,所以涉及到的知识范畴比较小,都是些基础的东西。

1、目录结构

除那些默认目录之外,我们在项目中又另外加了一些自定义的目录来做不同的事情。

1.1 errros/。在app/目录之下,内容是各种自定义的XxxError类。使用异常机制能够使得代码更加清晰,流程语义更准确,更好地实现模块化的程序结构。

1.2 validators/。在app/目录之下,内容是继承自ActiveModel::EachValidator的各种验证类。使用自定义验证类能够使代码更加简洁,复用性更强。如:
validates :username, :availability => true, :legality => true, :username => true, ......

这里面就使用了三个自定义验证类:可用、合法、符合用户名规则。

1.3 workers/。在app/目录之下,内容是resque任务的定义类。

1.4 其它和项目相关的目录。比如在项目根目录下,我们加了一个monitor/目录,里面是resque和redis的监控脚本。因为监控脚本在概念上属于项目外层,所以放到根目录下面,不隶属于app/。

2、使用组件

2.1 rails 3.0.8。这个没什么可说的,用蜂蜜,川贝,桔梗,加上天山雪莲配制而成,实在是居家旅行、杀人灭口之必备良药。不过我们在3.0.8上吃了点苦头,丫把safe_buffer设置为不可改动,结果页面片段缓存的cache方法中的slice!触犯了这个禁条,网站首页直接挂掉。还好,发现这个问题是晚上10点,没有造成太多损失。3.0.9已经修正了这个大bug,请各位不必多虑。

2.2 mysql2。舍弃了mysql驱动,使用mysql2。不过要设置为'< 0.3.0',0.3版的mysql2是配合rails 3.1的。

2.3 ruby-oci8、activerecord-oracle_enhanced-adapter。连接公司oracle数据库取行情数据的。还需要安装oracle的instant client,把安装目录添加到/etc/ld.so.conf.d里,然后ldconfig。有想用oracle的可做参考。

2.4 nokogiri、yajl-ruby。正好项目中也要用到nokogiri,所以就干脆替代了rails自带的xml和json解析器。

2.5 authlogic、cancan。比较了一下authlogic和devise,感觉各有利弊。因为authlogic对于namespace的处理比较灵活,而且也利于第三方身份验证的扩展,比较适合我们的需求,所以最后选了authlogic。cancan对于不是很复杂的权限验证,也差不多够用了。更细粒度的权限系统,恐怕就得根据需求自己定制了。

2.6 acts_as_list、acts_as_state_machine、will_paginate。前两个不解释。will_paginate的rails3版本已经很久没更新了,不知道作者是恋爱了还是失业了。kaminari是个很好的替代,只是有些功能还没完善,是否可以完全替换will_paginate有待论证。

2.7 ckeditor、paperclip、rmagick。其实富文本编辑器已经有不少了,比ckeditor好的也不乏其数。不过具备相配合的成熟gem的,恐怕目前还只有ckeditor。如果不嫌麻烦,可以找个更好的编辑器,直接挂上去用,或者自己写gem挂到rails上。

2.8 redis-store、SystemTimer、mongoid。使用redis作为默认的rails缓存,SystemTimer是redis client等几个gem要求使用的,ruby 1.8.7的timeout不可靠,我见到的几个gem的作者都强烈建议使用SystemTimer。mongoid支持rails3,所以就没用mongo_mapper。mongoid配置简单,语法很不错,功能比较强大。

2.9 resque、resque-scheduler、eventmachine。研究过twitter当初做的starling和workling,勉强能用,但配置很复杂,而且很久不更新了,就始乱终弃之。resque套件另行开文,在此不多说。

2.10 formtastic。formtastic号称是语义表单,实际用起来还是挺不错的,erb上的代码简洁多了,学习曲线也不高,一看即会。而且formtastic扩展性非常好,我们修正了和ckeditor的接口,还自定义了日期选择(date_picker on jquery)、日期选择组(date_selects)和验证码(captcha)控件。

2.11 client_side_validations。这年头网站上没个客户端动态验证,出门都不好意思跟人家打招呼。它能够直接使用model中定义的验证规则,DRY得很。而且能够和formtastic无缝整合。另外也很好扩展,我们利用回调加上了动态验证时的绿对号红叉号的小图片。

2.12 capistrano、capistrano-ext。代码发布管理的。如果你有不同开发环境的十几台服务器需要依次发布代码,就知道这东西有什么用处了。同样,这部分将另行开文。

3、配置

虽然说“约定优于配置”,但也不能没配置。不过如果只要配置配置就能搞定,总比写代码好多了。

3.1 自定义配置。项目中要使用到一些自定义的配置,比如oracle数据库的地址、redis服务器地址等等,而且开发环境和产品环境的还不一样。我们在config/目录下放了一个configuration.yml,里面区分出不同的environment,各个env下写入各自的配置。rails初始化的时候读取该yml文件,把相应env的配置以hash存入全局变量。以后以此全局变量来取得配置值。

3.2 系统配置。rails3的系统配置大部分都在config/application.rb中。

3.2.1 config.autoload_paths里要加上#{config.root}/lib,3.0版本里不再自动加载lib/目录。

3.2.2 数据库存储时间的字段默认使用UTC的时区,显示这些字段时要加time_zone显式转换。如果你的项目确认一辈子都在天朝玩,不想加上啰里啰嗦的显式转换,可如此设置:
config.time_zone = 'Beijing'
config.active_record.default_timezone = :local


3.2.3 诸如ckeditor这样的组件要用到i18n,为了不出问题,最好还是显式指定项目的语言:
config.i18n.default_locale = 'zh-CN'
I18n.default_locale = 'zh-CN'


3.2.4 日志数据太多,可设置自动轮换,每周换一个新的文件:
config.logger = Logger.new(config.paths.log.first, 'weekly')


3.2.5 更换默认缓存和解析器:
config.cache_store = :redis_store, ‘redis://xx.xx.xx.xx:6379’
ActiveSupport::XmlMini.backend = 'Nokogiri'
ActiveSupport::JSON.backend = 'Yajl'


3.2.6 扩展css和js命名:
config.action_view.stylesheet_expansions[:formtastic] = %w(formtastic formtastic_changes)


4、相关问题

4.1 初始化顺序。功能模块和某些配置的代码,有些在config/application.rb中,有些在config/initializers目录下的.rb里,有些库在lib/下面,这就涉及到一个rails初始化顺序的问题。如果代码执行的顺序不对,就会得不到预期的效果,或者会出一些莫名其妙的问题。rails3启动时的初始化顺序大致如下:
config.ru -> config/environment.rb -> config/application.rb -> config/boot.rb -> rails framework -> bundle gems -> configs in config/application.rb -> alphabetical .rb files in config/initializers

以上顺序未做深入研究,不保证完全正确,权威指南请移步官方文档

4.2 sendfile。如果用nginx passenger做rails应用服务器,而且使用send_file或send_data来发送比如需要先身份验证等特殊需求的文件,需要在config/environments/下面的配置文件中设置:
config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect'

否则send_file送出的文件大小为0。

4.3 本地化。需要翻译输出本地化文字的时候,尽量在config/locales/下面的相应文件里定义,这样能够精简erb或model的代码,职责也分得很清楚。目前我们在locales下面放了authlogic、formtastic、model中字段中文名和rails系统信息的中文翻译。

4.4 路由。rails3的routes语法改动比较大,而且写起来很自由。从项目管理的角度来说,有必要对routes的写法做统一的培训,使团队成员都真正理解routes的语法规则和适用环境,能统一使用最优写法的就尽量使用,实在不行再用其它写法解决。这样routes风格会比较统一。而作为反例,现在我们项目里的routes就是大家各显神通,什么样的写法都有,很不利于沟通和维护。

4.5 js框架。rails 3.0的默认js框架仍然是prototype,在jquery大行其道的今天,这个做法有点逆潮流而动。作为某些简单的js功能,用js generator是省时省力的做法,代码也干净。找了一个N年前就不更新的rails2的jquery rails,改了改使之适用于rails3,简单功能先凑合着用了。还好,3.1终于把默认js框架改成jquery了,当真是从善如流,幸甚至哉。

4.6 测试效率。即使在ubuntu平台上,跑rspec时rails所做的前期准备工作现在也延长到了好几秒钟,作为珍惜生命的开发人员,这几秒钟是难以忍受的。我们引入了spork作为测试的加速器,它会事先prefork出完整的测试环境,节省了初始化加载的时间。不过很不幸,我们现在做的rspec很少,所以在spork方面不做太多发言。

5、调优

在江湖的传说中,很多哥都会用“效率低下”来攻击rails。不过作为一个非计算密集型的项目,我们很少会注意到rails在代码执行上有瓶颈。但是在以下几个方面,我们还是感觉到了rails的某些不足,也尝试着做了一些优化。就效果来看,虽然没有数量级上的提升,但作为项目来说基本达到了要求。

5.1 应用初始化。rails3引入了rack作为底层架构,在架构层面上比rails2更为复杂,所以在应用的初始化时耗时相对较长。我们通过设置passenger_min_instances,提前多启动几个实例,减少用户访问时启动实例的时间。另外使用passenger_pre_start http://www.xxx.com/来初始化rails应用,减少初次访问的响应时间。不过比较郁闷的是,passenger_pre_start貌似效果并不是很明显,而且不支持touch restart.txt的重启,不知道以后会不会好一些。

5.2 虚拟机参数。即使是ree,ruby虚拟机的默认参数也基本上不满足普通应用的需求。我们参考了网上有关twitter和37signal的参数值,修改配置如下:
RUBY_HEAP_MIN_SLOTS=500000
RUBY_HEAP_SLOTS_INCREMENT=250000
RUBY_HEAP_SLOTS_GROWTH_FACTOR=1
RUBY_GC_MALLOC_LIMIT=50000000
RUBY_HEAP_FREE_MIN=100000


5.3 erb解析。rails3的erb解析效率还是比较低的,听说默认的erb解析器erubis还是用c写的,不知道是我们的服务器不够强劲还是效率本来就如此。我们网站的首页大概有1000行erb,在使用了新的虚拟机参数之后,渲染时间大约在1秒钟左右。这个时间在用户体验上属于不可接受的范围。

我们把首页中渲染耗时较长的代码独立成片段文件,每个文件里面全部使用片段缓存机制。例如:
<% cache "recommend_#{$recommend_pageid}" do %>
……
<% end %>

其中$recommend_pageid是rails在初始化时计算的该片段文件的md5值,这样如果该片段文件有改动,缓存中就不存在这个新的key “recommend_xxxxxx”,rails将重新生成该片段的缓存。这个方法既可使用片段缓存提高渲染速度,又可实现片段文件改动时的缓存自动更新。

使用片段缓存之后,首页渲染时间降低到了200ms左右,基本满足了要求。当然我们还留了一部分页面代码没做缓存。作为一个懂人情讲政治的开发团队,要给自己留出足够的业绩提升空间以体现自身价值,并且给领导留出足够的命令空间以展现领导权威。这样下一次领导再让你进一步缩短首页访问时间时,双方可皆大欢喜。

6、rails on windows

首先我承认,windows确实很不适合rails开发,尤其是那个执行效率,生活在mac和ubuntu上的幸福的人儿是永远都体会不到的。不过,如果rails只是我生命中的一小部分,其它大部分事情我确实需要在windows上做,而且我还很不喜欢虚拟机,那就要研究在windows上开发rails了。本节内容仅是给喜欢windows的同学提供一点参考,ubuntu和mac控可鄙视加无视。

其实解决方案很简单,就是使用rubyinstaller,同时安装devkit。基于mingw32的这套系统应该还算不错,到目前为止,一般的需要编译的gem象mysql2、nokogiri等等都没问题,最多也就是加几个参数,便可编译安装。迄今只有SystemTimer因为使用到了linux的底层SIGALRM而无法安装,不过也可以想个办法绕过去即可,不影响实际使用。

我的操作系统是windows 7 sp1 ultimate x32,不要用x64,x64下的mysql2安装会有一些莫名其妙的问题。感觉x32位还是比x64方便,一般不会出兼容性问题。至于4G内存的限制,打个补丁就行了。
分享到:
评论
17 楼 wowpzp 2011-06-30  
请问楼主acts_as_list、acts_as_state_machine 应用在什么场合呢?有什么优点呢?谢谢!
16 楼 keer2345 2011-06-30  
rubyinstaller.org 是不是被墙了?打开不了页面,唉
15 楼 seamon 2011-06-27  
edokeh 写道
想知道LZ是如何部署的,不知道能不能再写一篇文章


部署的会写,可参见第一篇末尾的计划。不过什么时候写就不保准了,尽快吧。
14 楼 edokeh 2011-06-20  
想知道LZ是如何部署的,不知道能不能再写一篇文章
13 楼 richyzhang 2011-06-14  
rjs已经被抛弃了。rails3.0的时候已经很明显了。对新手来说,rjs还是很棒的,可以一点不懂js照样写出dhtml和ajax的应用。然而,随着越来越多的js高手的出现,rails团队自身对js的熟练,现在提倡直接写js。不过js虽然很强大,却难看了点,于是又搞出了coffeescript。

你说的replace_html基本上现在可以这么写

<%=link_to “say hello”, { :controller => “welcome”, :action => “say” }, :id => “ajax-load”, :remote => true, “data-type” => “html”%>

:id指明了要replace的内容,date-type说明返回的是一个html,:remote表示是一个ajax调用。
12 楼 seamon 2011-06-14  
QuakeWang 写道
引用

4.5 js框架。rails 3.0的默认js框架仍然是prototype,在jquery大行其道的今天,这个做法有点逆潮流而动。作为某些简单的js功能,用js generator是省时省力的做法,代码也干净。找了一个N年前就不更新的rails2的jquery rails,改了改使之适用于rails3,简单功能先凑合着用了。还好,3.1终于把默认js框架改成jquery了,当真是从善如流,幸甚至哉。

在3.1之前如果想用jquery的话,推荐
https://github.com/rails/jquery-ujs


我们现在用的就是ujs,不过ujs只是在表单等基础层面上替换为jquery,我说的是用jquery实现rjs,象replace_html这些简单的功能。

现在rails 3.1用的是jquery-rails,也兼容3.0。不过还是不支持rjs,官方的意思是rjs已经被踢出去了,默认不再支持。prototype和rjs被移到prototype-rails了。

jrails的作者问过jquery-rails的作者,问他们想不想加入jquery对rjs的支持,结果人家没鸟他,意思是3.1已彻底放弃rjs了。看来谁想在3.1继续用rjs又不想引入prototype,得寻求其它解决方案,或者自己搞一个jquery-rjs。
11 楼 edokeh 2011-06-13  
第一次听说client_side_validations,之前我看到最好的前端验证框架是jquery validate,不知道client_side_validations的功能与定制性究竟如何,但是能与后端公用一套校验规则,还是很吸引人的
10 楼 jn615 2011-06-12  
学习了, 不错的东东
9 楼 agile_boy 2011-06-12  
受教了,谢谢分享。
8 楼 QuakeWang 2011-06-11  
引用

4.5 js框架。rails 3.0的默认js框架仍然是prototype,在jquery大行其道的今天,这个做法有点逆潮流而动。作为某些简单的js功能,用js generator是省时省力的做法,代码也干净。找了一个N年前就不更新的rails2的jquery rails,改了改使之适用于rails3,简单功能先凑合着用了。还好,3.1终于把默认js框架改成jquery了,当真是从善如流,幸甚至哉。

在3.1之前如果想用jquery的话,推荐
https://github.com/rails/jquery-ujs
7 楼 活靶子 2011-06-11  
  感谢~感谢~
6 楼 seamon 2011-06-10  
Hooopo 写道
引用
不过我们在3.0.8上吃了点苦头,丫把safe_buffer设置为不可改动,结果页面片段缓存的cache方法中的slice!触犯了这个禁条,网站首页直接挂掉。还好,发现这个问题是晚上10点,没有造成太多损失。3.0.9已经修正了这个大bug,请各位不必多虑。

6月8号一天rails版本4连发就是fix这个问题。。
引用
Rails 3.0.9.rc1 has been released! 

Rails 2.3.12 has been released!

Rails 3.0.8 has been released!

Rails 3.1.0.rc2 has been released!

官方博客还更新了一篇文章:http://weblog.rubyonrails.org/2011/6/8/potential-xss-vulnerability-in-ruby-on-rails-applications


嗯,那篇文章是说为防止XSS攻击,所以才设置safe_buffer不允许修改,但是没说那个cache的bug。感觉这个bug还是比较严重的,凡是使用片段缓存的页面,肯定都要挂。比较严重的事故啊,测试不到位。

官方反应还是很快的,3.0.9rc1马上就修正了这个问题,改了actionpack里面的cache_helper.rb,没有直接output_buffer.slice!,而是先to_str了一下,然后slice!,再new成output_buffer。我也是参照官方的解决方案,直接把3.0.8的代码给改了,反正也用不了几天,估计3.0.9正式版很快就会发布。
5 楼 Hooopo 2011-06-10  
引用
不过我们在3.0.8上吃了点苦头,丫把safe_buffer设置为不可改动,结果页面片段缓存的cache方法中的slice!触犯了这个禁条,网站首页直接挂掉。还好,发现这个问题是晚上10点,没有造成太多损失。3.0.9已经修正了这个大bug,请各位不必多虑。

6月8号一天rails版本4连发就是fix这个问题。。
引用
Rails 3.0.9.rc1 has been released! 

Rails 2.3.12 has been released!

Rails 3.0.8 has been released!

Rails 3.1.0.rc2 has been released!

官方博客还更新了一篇文章:http://weblog.rubyonrails.org/2011/6/8/potential-xss-vulnerability-in-ruby-on-rails-applications
4 楼 wowpzp 2011-06-10  
学习了!感谢楼主!
3 楼 bluebu 2011-06-10  
希望rails3.1中的erb解析效率能够提高些。。。
2 楼 xinghu 2011-06-10  
如沐春风~~
大牛你好 !
1 楼 yang_kunlun 2011-06-10  
畅快啊, 楼主功力深厚啊

相关推荐

Global site tag (gtag.js) - Google Analytics