Ruby/Rails为什么不如以前热门了?

最近在知乎上看到了一个问题,问“Ruby和Ruby on Rails在2017年还有前途吗?”我觉得这个问题很有意思,因为其实Ruby圈子里不少很资深的朋友,都转行去做别的了,有做前端的,有做Go,还有像我开始做Nodejs了。给人的感觉就是Ruby不行了,圈子也不够活跃了,
下面我来分析一下Ruby/Rails为什么最近声音小了。首先看大公司为什么很少用rails,据我所知有
1. rails的性能和内存占用不理想,规模效益不高
2. ruby作为动态语言在大团队开发上存在劣势,不能像java有接口和静态类型检查,能够帮助大团队在开发期减少Bug。
3. 小众语言,招人(相对)困难
4. rails本身是单块设计,而且很多地方并不OO,不适合大公司拆分、细化、优化的诉求

而rails更多是创业小公司在用,我的经验包括:
1. 全栈框架,有自己的前端逻辑
2. 完善的生态
3. 开发速度快,对人员数量要求少
4. 学习曲线很线性,容易培养(全栈的)开发人员

对于小公司来说,本身资金有限,人力成本又占主要部分,产品不确定性大,所以选择走小团队,快速开发的模式是很自然的事情。而大公司,往往有完善的体制——招聘、培训、管理,等等——支持,所以往往是希望能通过增加人手来扩大生产规模以及完成更多的产出,这就要求开发工具有足够的“工程性”。这跟Rails的理念就是相违背的,而Ruby的工程性也不如Java之类的好。

大家再回想一下这几年中国经济形势如何?实体凋敝,房价暴涨,很多人都觉得创业还不如买几套房子。这样创业公司少了,用Ruby/Rails的自然也少了。

再看这几年的技术发展趋势,一个是经过多年的发展,当初Ruby/Rails的很多先进思想也都被其他语言和工具吸收了,开发效率上的领先已经达不到最早那种数量级的差异。
同时很多开发者已经熟悉了自己的一套框架和工具链,如果实现相同功能,没有十足的必要学习另外一种新的技术。

而只有前端不一样,浏览器只支持JavaScript,整个前端的生态又顺理成章建立在了nodejs之上。加上手机客户端又适逢新兴的移动互联网浪潮,需求量突飞猛进。前端、客户端之前的积累也比较少,加上需求的推动,有很大的空间来造轮子。

所以Ruby/Rails近几年声音变小也是正常现象,即使我认为目前在开发体验上还没有能超过Rails的全栈框架。

从产品角度来看,早年开发产品拼技术,主要看你东西能不能做出来。后来开始拼产品设计,又讲究快速开发和快速试错。以前在Web时代,Rails在这些方面都有优势。而到了移动时代,产品设计和快速迭代的主要部分从后端移到前端,让后端开发变成了一个配角,尤其是后端开发在早期阶段的重要程度也降低了。

然而事到如今,各端入口都被占据,流量、用户基本被巨头们瓜分干净,各种现成的平台服务也层出不穷,又进一步让技术的重要程度又降低了。想想做一个公众号,用现成的平台,经营好粉丝就能拉投资捞钱;或者在现有平台上开个微店来做生意。现在很多创业门槛完全不在技术方面,技术的重要程度被大大降低。

而往后看,VR、人工智能、大数据、IOT等等也都不是Ruby所擅长的领域。

种种加起来,可以看到Ruby/Rails几乎不可能再掀起新的浪潮。总结了这么多,就是,Rails本身所擅长的领域在现在已经变得很狭窄也不那么重要了,所以才声音小了。任何技术也都有他的生命周期,Ruby/Rails是非常优秀的技术和工具,如果你要做的事情符合他的目标,那它依然是一个很棒的选择。

链接:https://zhuanlan.zhihu.com/p/25007358

Ruby的类成员作用域与self

请考虑一下代码

结果为

arst
arst
#<NoMethodError: private method test3' called for Test:Class>
#<NoMethodError: private method
test' called for #<Test:0x2c28060>>

类方法Test.test是不受作用域修饰符private影响的,可能原因在于self.的声明方式其实只是class<<self的语法糖。

Rails SQL Session Store优化版

问题根源

原始的ActiveRecord会话仓库很慢。对于低流量的网站而言没有什么问题,但是对于大一点的而言就慢了。首先,它的慢是因为ActiveRecord本身比较慢。虽然这是一个强大的ORM框架,但对于像会话管理这种简单的任务而言就是杀鸡用牛刀了。

还有其他的解决方案如cookie会话仓库(会话长度有限,不能在会话中存放敏感数据),memcached(无法持久化+难以实现高可用性方案)。

这就是为何要创建SqlSession仓库的原因。它直接操作mysql的数据库API,要比原始的AR会话仓库快很多。不过有时候它还是比较慢,因为:

  • 每次访问都会创建、更新会话 – 任何机器人或者偶然的访客都会在数据库中创建一条会话记录,最后导致会话表里面会有成千上万的无用记录,但其中99%的访问其实是不需要任何会话更新的。
  • 它使用32位字符串作为会话记录的键 – 所有RDBMS在处理字符串索引都要比整数慢很多,所以使用整数更好,然而我们的会话ID非常长,同时这些会话仓库都直接使用他们作为表索引。
  • 使用了auto_increment 主键,对于MySQL 5.1.21之前的版本都会导致InnoDB使用表级锁。在不必要的插入上使用表级锁会给大型网站造成奇怪的问题。

解决方案

FastSessions Rails插件便是作为对于以上几个问题的解决方案而诞生的。

首先,我们从会话表中去掉了id字段,所以我们无须用到auto-increment锁。接下来为了让查找更快,我们使用了以下这些技术:不使用(session_id)作为查找索引,使用(CRC32(session_id), session_id)——双列键,可以帮助MySQL更快地找到会话记录因为键的基数更高(这样,mysql可以更快地找到记录而不用检查很多索引行)。我们测试过这种方法,在大会话表中显示了10-15%的性能提升

最后,也是最强的优化是,对于空会话不创建数据库记录,同时如果数据没有在请求处理过程中没有更新过,则会话数据不会存回数据库。这个更改基本上可以减少50-90%的插入数量(根据应用程序的情况)。

那么,你肯定在想,用了这个插件之后会话究竟能快多少?这很难说。结果要看你是怎么操作会话的:如果你很少更改会话数据(如登录时储存用户id),那么可能会有90%的性能提升,但如果每次访问,你都要给用户会话写入些信息(比如最后一次访问时间last_visit_time),那么根据服务器的负载和会话表的大小,可能有5-15%的性能提升。

你只需要安装一个简单的插件,便可以自动实现上面这些更改。

我们解决了AUTO_INC锁的问题并去掉auto-increment键之后,又引入了一个新的问题,我在这里想说一下。这个问题是这样的。InnoDB会根据主键将所有数据分组。这意味着当我们使用自增长主键并向表插入记录时,会话记录会被组到一起,顺序地存储在磁盘上。然而如果使用比较随机的值(如一个随机会话id的crc32值)作为主键,那么每一个会话记录会被插入到属于它自己的不同的地方,那么会产生一些随机I/O,这对于I/O有限制的服务器不是很理想。所以,我们决定让用户自己选择在部署的时候使用何种主键,当你想在MySQL 5.1.22+上使用这个模块的话,可以设置

CGI::Session::ActiveRecordStore::FastSessions.use_auto_increment = true

这样在InnoDB中会连贯地插入数据。另一个情况当你的MySQL服务器的I/O有限制,不想因为随机主键而增加随机I/O,也可以这样设置。

如果你不想丢失使用AR会话插件创建的旧会话数据,你可以设置

CGI::Session::ActiveRecordStore::FastSessions.fallback_to_old_table = true

这样当某些session_id在新的会话表中找不到的时候,就会回去访问旧的会话表。旧会话表的名字可以使用CGI::Session::ActiveRecordStore::FastSessions.old_table_name 变量进行设置.

这个选项会使会话变慢所以我建议只要在升级到新会话表的时候才使用。在这种情况下,新的会话数据就会存入新表中,当到了会话超时期限的时候,就可以删除旧表了(我们用了两个月的期限,过了两个月之后,我们就可以删除旧表,并将此选项关闭。)。

安装

安装FastSessions插件十分简单,只需以下几个步骤:

  1. 将该插件代码从我们的SVN库中安装到vendor/plugins目录中(可以使用./script/plugin install安装,或者piston import命令进行安装——看你喜欢)例如:

    $ piston import http://rails-fast-sessions.googlecode.com/svn/trunk/ vendor/plugins/fast_sessions
  2. 在config/environment.rb文件中启用ActiveRecord会话仓库:

    Rails::Initializer.run do |config|
    ......
    config.action_controller.session_store = :active_record_store
    ......
    end
  3. 为新的会话表创建数据库迁移:

    $ ./script/generate fast_session_migration AddFastSessions
  4. 如果需要,可以打开新创建的迁移脚本并更改表名table_name和插件use_auto_increment参数。
  5. 运行数据库迁移:

    $ rake db:migrate
  6. 启动应用程序并尝试进行一定会保存数据到会话的操作。然后检查fast_sessions会话表(如果你没有改名字的话)有没有这条记录。

下载

该插件的最新版本可以在它的项目网站或在 SVN仓库中找到。该插件由Alexey KovyrinPercona的MySQL性能专家)制作。开发由Scribd.com赞助。

关于《浅析Rails部署》

我之前写的文章《浅析Ruby on Rails部署方案》受到不少同学的关注,在此首先感谢大家。

但是也有同学对此提出了一些疑问,我经过检查,发现文章确实存在很多漏洞和不足:

  1. Lighttpd作为负载均衡反向代理时,无论是链接FastCGI还是HTTP后端,KeepAlive链接默认都是关闭的
  2. Nginx的FastCGI模式,默认也是关闭持久链接的
  3. 缺少了一些重要的前后端搭配的方式
  4. 对于Rails应用的内存占用也应该考虑在内

我会针对这一些问题,重新设计测试案例,并重写该文章。再次感谢大家的关注。

Slapp: 简易聊天墙的Merb教程

有问题或评价,请联系: socialface@gmail.com

程序截图: http://www.socialface.com/slapp/screenshot.jpg

简介

欢迎来到Slapp的教程。本文的主要目标是通过构建一个简易的聊天墙应用来介绍一下Merb微框架的主要组件。

本文其次的目标是成为最好的Merb开放教程并能不断更新。同时,我们希望本教程可以逐渐变得丰富来展现Merb框架的所有方面和开发方式。

许可

This tutorial is Copyright 2008 Social Corp. and is licensed under a Creative
Commons Attribution-Noncommercial 3.0 United States License, available at:

相关的源代码以MIT形式的开发源代码许可:

直接浏览代码:

也可以直接下载:

参与人员名单

本教程最初由来自#merb的Slurry撰写。Slurry在撰写本文时主要参照了Merb的官方文档[^a]以及#merb IRC频道的内容。

在学习Merb的RSpec的过程中,还咨询了John Hornbeck的Blerb[^b],参考了Tim Connor的“Isolate controller and view testing in merb”一文[^c]——虽然帮助很大,真正掌握Merb/Rspec还是得益于来自#merb的benburkert。

中文版由ShiningRay翻译

前期决定

设计上来说,Merb是一个ORM无关的框架。当然,这仅仅是表示有不同的模型层可以选择。对于Merb v0.9.2来说,包括:DataMapper、Sequel和ActiveRecord(来自Rails)。

尽管DataMapper和Sequel都是很好的选择,但现在关注Merb的主流人群基本上都是来自Rails背景;因此,我们在本教程中会继续使用ActiveRecord。

1.) 创建模型

在像Merb这样快速成长的社区中,一个问题可能只需更新或者重装Merb相关的包(gem)就能简单解决,所以让我们先花点时间这样准备一下:

完成了前两行命令后,Merb、ActiveRecord以及Rspec应该已经安装好或已经更新了,同时后两行命令则应该创建了一个初始的空Merb应用。

从这里开始,我们就要告诉Merb:我们要怎样用ActiveRecord,要使用哪个测试框架,以及需要载入哪些确切的merb_helpers包(如表单相关的东西)

编辑:slapp/config/init.rb 并取消第2742的注释,同时将:dependency "merb_helpers" 添加在
Merb::BootLoader.after_app_loads do 这一行之前:

现在我们已经告诉Merb要使用ActiveRecord: use_orm :activerecord, 让我们来生成第一个模型:

靠,居然没效。不过等等,你应该还有一个全新的slapp/config/database.yml.sample 文件等待配置,对吧?[^1]

好,现在你要做的就是将这个文件名字改成database.yml并在其中插入合适的数据库链接信息,像这样:

让我们重新运行上面的merb-gen命令,不过这次我们还要再加上一些Post的默认属性:

如果一切正常,那么第一个模型类就有了。让我们使用rake对数据库进行迁移,来加上表:

现在,Slapp应该有一个有效可用的Post模型了。为了以防万一,我们将介绍RSpec[^2].

2.) RSpec

RSpec——你可能已经知道了——是Test::Unit的另一种替代测试方案。与RSpec交互主要通过rake任务和spec命令:

或者,更加详细的:

(重要:这里使用的rake任务来自Merb前沿代码,应该很快会发布为标准包。在那之前,可以使用以下同等任务:
rake specs 以及 rake spec TASK=controllers/pages)

两个任务会运行slapp/spec/*中的任何代码,简洁起见,我们这里会使用rake。

让我们再次运行测试:

如你所见,Merb已经为我们创建了一个默认的测试,但是他还不能通过:

打开: slapp/spec/models/post_spec.rb 看看这个测试在哪里:

将该spec改成实用的代码,比如:

该测试看上去好像不多,但是它确实可以验证Merb、RSpec、ActiveRecord和我们的数据库都已经安装成功并工作正常。

同时,如果我们在此运行新的spec,数据库又出现一个问题。确切地说,我们忘记了创建slapp_test 数据库并将slapp_development的结构复制过去。

重新运行spec:

这时成功在向我们问候:1 example, 0 failures,这一行表示所有的spec都通过了。更重要的是,我们遇到并克服了实际使用RSpec的第一个问题。

3.) 控制器

虽然现在从技术上说我们没有控制器也能启动Merb,但是基本上作不了什么。事实上就是什么都作不了,我们还是先来创建一个控制器:

如你所见,Merb的控制器的命名方式是模型名(或者资源等)的名字复数化,且不使用Controller后缀。

看一下slapp/app/controllers/posts.rb,你应该看到我们新的Posts控制器里有一个默认的#index动作。另外,Merb还应该创建了一个新的spec: slapp/spec/controllers/posts_spec.rb ,里面的内容应该类似于:

让我们编辑:slapp/spec/controllers/posts_spec.rb,更改内容为:

指定控制器是比较直观的,在上面的例子中,我们描述了Posts控制器(从dispatch_to中返回的)有一个#index动作并且它能被外部世界成功调用(即,它返回一个HTTP 20x 代码)[^3].

我们想再次运行spec,但是由于我们没有添加任何模型或视图测试,所以让我们执行更加明确的“仅控制器”的rake任务:

成功的测试结果:

漂亮。现在我们已经有了一个可以工作的控制器和一个有效的模型——我们只缺一些好的视图了。

4.) The View from Above

前面当我们创建Posts控制器时,Merb同时也为#index动作创建了一个草图。位于:slapp/app/views/posts/index.html.erb,你也许会看看里面有什么,然而,让我们先暂时忽略这个视图,并回到控制器。

slapp/app/controllers/posts.rb 中,我们执行一个简单的 ActiveRecord #find
并在#index动作中将结果存储为一个实例变量:

然后我们确认该动作仍然是可以调用的:

就和Rails(或者其他Web框架)中一样,在控制器中创建的实例变量可以在对应的视图中调用。

在本案中,我们可以回到:slapp/app/views/posts/index.html.erb 并将临时文本替换成显示@posts变量内容的代码。

为了能保持模块化,我们将使用Merb #partial[^4] 功能来达到这个目的。

slapp/app/views/posts/index.html.erb 的内容替换成:

不看HTML,调用#partial应该还是比较容易理解的——
我们想多次渲染slapp/app/views/shared/_post.html.erb 视图来呈现@posts的内容。

现在创建: shared/ 目录以及: _post.html.erb 文件:

并编辑 slapp/app/views/shared/_post.html.erb 的内容为:

上面调用: partial("/shared/post", :with => @posts) 会反复传递一个单个post对象给视图_post.html.erb并渲染。

5.) 启动Merb

现在我们有了模型、控制器、以及一个视图,让我们启动Merb:

你应该看到了一个普通的欢迎页,再转到:

这时你应该看到slapp/app/views/posts/index.html.erb的内容了。当然,由于我们还未创建任何帖子,所以应该看不到任何东西。

让我们使用交互Merb会话(其实就是一个在Merb应用的内容中启动的IRB)修正上面的问题:

使用典型的 ActiveRecord #create 方法,我们现在创建了一个Post。重新载入
Posts#index 页面:

我们应该成功地看到了新的帖子。

6.) 特殊的视图

现在我们已经实现了视图,也许他们不会经常更改,让我们先描述他们。

首先,创建目录和spec文件:

然后将一下代码放入slapp/spec/views/posts/index_spec.rb

当使用RSpec描述对象时,常常需要在运行测试的前后维护测试特定的内容。毫不奇怪,RSpec向我们提供了#before#after块来实现这个目的。

回到代码中:我们在#before块中首先做的是从我们的 Posts 创建@controller实例。下面我们使用fake_request助手[^5]来模拟HTTP请求。

回想一下我们的视图:

我们知道我们还需要一组帖子来进行测试,碰巧,这就是#before块的第二和第三行所做的事情:

@controller.instancevariableset(:@posts, @posts)

这里,我们仅仅将插入了一组记录并保存为@controller@posts实例变量。记住,调用Posts控制器的#index动作和我们之前所做的没有什么区别,除了我们使用了一个ActiveRecord的#find,而不是手工使用#new创建帖子:

前面的Posts控制器Our Posts controller from earlier:

最后,#before的第四和最后一行渲染了视图并将响应的主体(本案中是HTML)放入了@body 实例变量。

(本质上来说,我们是使用fake_request来“查看”Posts#index动作。)

现在,我们的控制器已经设置好了,同时视图也渲染了,我们就开始列出我们对视图中应该有什么的预期。[^6]

首先,我们描述HTML里应该最外面有一个div来放每一个单独的帖子的div:

下面,我们断定容器div确实包含着帖子的div:

然后,我们进入每个帖子的div来验证内容准确地匹配对应的Post:

最后,我们使用#after块来删除在#before块中创建的帖子:

尽管我们还没真正完成,我们先来验证一下整个应用:

7.) 表单创建

有了浏览帖子的能力之后,现在就可以实现同样重要的创建帖子的功能了。

打开slapp/app/views/posts/index.html.erb并在帖子列表下面添加该表单[^7]:

几乎不言自明,我们是要构建一个简单的表单,有一个文本输入框和一个提交按钮。

你应该已经注意到我们已经将表单设置为递交到Posts控制器的#create动作。我们需要实现这个动作,不过在我们继续之前,我们先快速描述一下这个表单。

编辑: slapp/spec/views/posts/index_spec.rb并在#after 块上面添加一下内容:

和前面一样,我们使用#match_selector 来断言表单、正文输入框以及提交按钮的存在。唯一不同的是我们使用了一个基于HTML属性的选择器[^8]form[@action=/posts/create]

Run the specs:

我们可以再次启动Merb来亲眼检验一下新的表单了。不过,因为我们已经使用了RSpec,这步不是非常必须的,我们可以立刻继续往下。

说道RSpec,这次,当我们在要去完成#create动作的时候,我们应该在写代码之前先写出该步骤的spec。

将以下内容复制到 slapp/spec/controllers/posts_spec.rb

这里,在#before块中,我们准备了一个只有一个:body键的@params表以便开始描述#create动作 。下面,我们列出了第一个预期:create动作在它成功创建一个帖子之后应该重定向到#index动作。

(这就是如果一个浏览器通过表单提交了某些信息,在我们的应用中能看到的情况。)

我们用一个lambda表达式检验一个帖子是不是被创建了,其中RSpec会调用两次:先执行一次,然后等相关的{...}块执行完之后再执行另一次。

这两次中,RSpec都会调用Post.count,如果两次调用返回不同的值,那么我们就能确信Post被创建了,那么这个块(该动作)就是成功的。

因为我们还没有编码#create,所以spec显然会失败:

切换到: slapp/app/controllers/posts.rb并再次复制以下内容:

现在我们定义了#create,现在回到spec文件,应该就可以通过了:

通过了这些spec,我们就有了一个可以正常工作的聊天墙了。

听起来是个好消息,我们也几乎就要完成了。我们还需要做得就是检验创建一个新的帖子需要一定的文本,否则则会出现一个异常。

8.) 收尾

现在,任何都可以点击 “Post Message!” 然后创建一个新的帖子。因为我们并不想让一堆空白的帖子占据聊天墙,所以我们应该在创建新帖子之前校验至少有一些文本被提交了。

因为本文是一个教程,我们不打算将所有东西都仔细进行合适的处理,所以这里我们直接使用ActiveRecord的validates_length_of过滤器。 ;-)

打开: slapp/spec/models/post_spec.rb 并观察我们现有的spec:

因为我们要校验正文文本的存在,这个spe已经不再有效,我们需要如下的内容来替代:

和平时一样,我们首先运行失败的spec来建立我们对于特定行为的预期:

然后实现上面提出的修正,在本案中,则是在slapp/app/models/post.rb中加入一样:

再次运行spec来检验我们的修正是否有效:

这时我们的模型完成了。让我们继续给Posts控制器添加一个spec——
我们需要描写当提交一个帖子没有包含正文的时候,我们没有真正去处理这个错误而已直接返回由我们的ORM抛出的异常。

编辑slapp/spec/controllers/posts_spec.rb并加入下面这个spec:

如你所见,我们仅仅是不带@params表来调用#create。这创建一个没有正文的空Post,这样就会导致ActiveRecord的校验失败,并抛出我们预期的RecordInvalid异常。

有了这个,我们的第一个聊天墙的版本就完成了。就和前面一样,你可以通过启动Merb并浏览Posts#index动作来试试程序:

最后的思考

从这里开始,你可能还有很多东西想添加,例如:分页、动态发布/更新、SPAM过滤器、文本格式化等等。

这些对于任何优秀的聊天程序都是很基本的,你都可以利用Merb来实现。

同时,别忘了浏览官方的项目首页看看有没有最新的更新、看看别人的版本甚至创建属于你自己的:

有任何问题/评价,请致电socialface@gmail.com或者在#merb找 Slurry

脚注

[^1]: The observant may have also just found their first “Merb” bug.. the
generator claimed to have made a “database.sample.yml” file, although the file
is really named “database.yml.sample”. :-)

[^2]: RSpec links in order of approximate handyness to the beginner:

[^3]: Merb RSpec controller matchers:

[^4]: Merb partials:

[^5]: Merb fake_request helper:

[^6]: Merb RSpec view matchers:

[^7]: Merb Form Helpers:

[^8]: Hpricot CSS Selectors:

浅析Ruby on Rails部署方案

2006初,我接到了公司分配的一个遗留项目,让我负责一个基于C/S的系统的服务器端。其实是系统是基于HTTP协议的,因为负责客户端的同事对于服务器端编程不甚了解,虽然使用PHP对熟悉C++的他来说是驾轻就熟,但是在进一步实现更多的功能和更高的性能上就捉襟见肘了。项目是在非常突然的情况下交给我的,因为该同事在客户端上有更多的事情要做。我在分析了他的数据库结构和PHP源代码之后,决定按照与客户端的通讯协议重写他的服务器端。为了能应付老板苛刻的时间限制,我打算使用正在学习的Ruby on Rails。后来,项目在功能上非常顺利地交付了。

两年过去了,随着客户端数量的不断增加、客户端功能的增加、与服务器端交互数据的增加、老板对功能的要求不断增加,我在这个项目上走了不少弯路,尤其是在部署——或者说是架构——方面。

我遇到的最大的问题就在于并发链接数上。服务器与客户端的每次交互的数据量并不大,但内容无法缓存。起初用的是Nginx/Apache+Mongrel 的部署方式,但当遇到大量并发请求时,常常会遇到Mongrel进程死掉的情况。而客户端的用户在无法登录客户端的时候,经常会反复尝试,加重了服务器的负担、导致最后所有的Mongrel进程都挂掉。

最后,经过不懈努力,在现有的3台低端服务器上,可以满足每天500万次的请求。在这里,我将我的一些心得和研究成果总结出来,与大家分享。


文档地址:http://docs.google.com/Doc?id=ddcvzh74_28f9xppqfh

文章发布在Google Docs上,欢迎大家在其上做批注,有意见和建议也可以在此留言。文章按照知识共享“署名 3.0 中国大陆”许可协议发布,欢迎转载。

Redmine

Redmine是基于Ruby/Rails的一个项目管理软件。比较类似的则是基于Python的Trac,相比之下,Redmine有很多优势:

  • 简单的安装、配置和部署
    Redmine利用rake、rails的db migration安装很方便,Trac则要用到命令行的trac-admin进行配置,以及每个项目有单独的ini配置文件
  • 方便的用户和权限管理
    Redmine支持多LDAP认证、还支持用户自己注册,然后通过邮件激活。Trac依然需要使用trac-admin来配置,而且默认的用户登录方式是HTTP验证,基于cookie的还需通过插件实现
  • 基于Web的多项目管理
    Trac创建和配置新项目需要使用trac-admin
  • Ajax
    Redmine通过Ajax在某些方面提供了更好的用户体验,如代码仓库的浏览
  • 多语言
    包括简体中文
  • 多种SCM
    包括SVN、CVS、Darcs、Mercurial、Bazaar,是通过调用它们的可执行文件来实现的。

trac的很多功能都需要通过trac-admin在命令行方式下进行配置,不易上手,这方面Redmine则十分方便。

其实功能方面,Redmine更多地是模仿Sourceforge的功能,比如新闻、文档、下载等,目的是建立这种适合团队协作的平台。我估计以后Rubyforge可能会迁移到Redmine上去。

升级到RubyGems 1.0

虽然前一段时间Ruby社区推出了很多重大的更新,如RubyGems发布了1.0,Rails发布了2.0,Ruby发布了1.9测试版。但是却潜藏了很多危险。比如在Windows平台下,升级了RubyGems之后,会导致我现有的Mongrel无法启动,原因在于RubyGems1.0修改了系统的识别,将mswin32改成了x86-mswin32,从而导致gem_plugin无法正确定位相应gem。

修复的方法也很简单,只需要先删除Mongrel再重新安装:

另外还在一些人的BLOG中发现Rails2.0刚发布时,是要求使用RubyGems0.9.5,也会出现一些问题。幸而我暂时没有迁移到Rails2.0上,也还没有遇到问题。

从这一个事件上也可以看出Ruby社区相对于Python/Perl的社区来说,还不是十分的成熟。

Ruby 1.9.0 发布

来自Ruby官方网站的最新消息,Matz已经发布了1.9的开发版本作为献给大家的圣诞礼物。

1.9的性能较1.8有大幅提升(请参考相关测试结果),并且添加了大量新的语言的特性

这无疑对于Ruby爱好者是一个福音,但前不久刚发布Rails 2.0还不能完全正常运行于Ruby 1.9之上,包括诸如Mongrel之类的其他组件,所以在很长时间内Ruby 1.8将仍然是主流的平台。不过相信Ruby社区和相关社区的朋友们会一起努力,使这个迁移快速而顺利地完成(就像当年Python 2.5发布的时候)

Rails + Memcached = Undefined Class/Module?

问题描述:
当使用memcached并将Model对象保存在其中时,若要取出这个缓存对象时,可能会找不到Model的类,并抛出“Undefined Class/Module SomeClass”的错误。
例如:

解决方案
要解决这个问题,可以在引用到该对象之间,先引用其类。比如,在前面的代码前面加入要引用的类Genre:

还有更好地方法是在Controller的before_filter中加载所依赖的所有Model:

结论
这个问题应该是Rails的一个Bug,不知道在2.0中有没有解决。我猜测是因为Rails中很多类信息是lazy load的,而从memcached中取出时没有附带类信息,也不知道如何加载,而通过上面的方法预先加载所需的类和其相关的类的信息,便解决了这个问题。