从C#.net到RoR - GuruDigger的的迁移经验分享

===广告部分,想看技术部分的可以直接跳过 :) ===

[url=http://gurudigger.com]GuruDigger[/url]是一个面向web开发者的社区,能够从用户认证通过的Email 出发,自动爬遍互联网,根据用户在互联网上的活动进行分析,对掌握的每项编程语言技能进行评分和排名:

[img]http://dl.iteye.com/upload/attachment/519131/aba005b8-3015-3cfa-8ef3-428e341a2ed4.png[/img]


还有头脑风暴板块和Guru燃料功能能够帮助用户实现他的各种好玩,甚至是稀奇古怪的Idea:

[img]http://dl.iteye.com/upload/attachment/519133/3b4b18b0-5d20-3737-b7f4-c481a20ce51c.png[/img]


===广告结束,以下是迁移经验分享部分===

GuruDigger之前是用C#.net开发的,最近迁移到了rails 3(3.0.9),迁移的主要原因:rails生产力高,便于后续维护。

因为是业余时间做的,前后差不多用了2个月的时间,统计了一下,我累计用了120多个小时
另外一个开发者[url=https://twitter.com/#!/linjunhalida]linjun[/url],因为是第一次接触ruby的关系,包括学习和开发,累计用了200多个小时。

对于后台开发,rails的效率没的说,但是前端还不给力,虽然和2.0 相比, 3.0的jquery + ujs好用了很多,可是很多时间还是花费在了和js/html/css上,这和我们2个开发人员都不擅长前端也有关系,目前用的css都是照扒旧版本的,后来还有专门的前端工程师帮我们改了很多。

1. 用户认证
Rails项目用户认证当然首选[url=https://github.com/plataformatec/devise]devise[/url],短短的几行配置和代码,就可以搞定一切关于注册,登录,忘记密码等一系列用户认证相关功能,再配合[url=https://github.com/intridea/omniauth]omniauth[/url],还可以实现Google/Twitter/QQ/新浪微薄等第3方帐号登录。

但是GuruDigger旧版本记录的用户密码是MD5加密,不够安全,所以在迁移的时候对devise做了一个扩展,将旧系统的MD5密码导入数据库(legacy_password_hash),用户在新系统第一次登陆的时候先用旧密码判断一下,进行密码迁移:
module Devise
module Models
module DatabaseAuthenticatable
def valid_password_with_legacy?(password)
if self.legacy_password_hash.present?
if ::Digest::MD5.hexdigest(password).upcase == self.legacy_password_hash
self.password = password
self.legacy_password_hash = nil
self.save!
return true
else
return false
end
else
return valid_password_without_legacy?(password)
end
end

alias_method_chain :valid_password?, :legacy
end

module Recoverable
def reset_password_with_legacy!(new_password, new_password_confirmation)
self.legacy_password_hash = nil
reset_password_without_legacy!(new_password, new_password_confirmation)
end

alias_method_chain :reset_password!, :legacy
end
end
end


2. 权限
使用的是cancan,它能够让你在一个集中的地方定义权限(Ability 类),而不需要分散在controller,views或者数据库查询中添加各种重副代码,比如我们定义了用户只能编辑、删除自己的idea或者project,只用在Ability里面定义如下:
can :manage, [Idea, Project, UserEmail], :user_id => user.id


在Idea Controller里面,就只用cancan提供的helper method load_and_authorize_resource加载当前用户有权限的idea,非常方便:
class IdeasController < ApplicationController
load_and_authorize_resource
def update
@idea.update_attributes!(params[:idea])
end
end


3. 文本编辑
因为是面向web开发者的社区,所以文本编辑器方面用了和Github一样的markdown语法,在前端编辑器用的是[url=http://markitup.jaysalvat.com/home/]markitup[/url],在后端markdown render html的功能上,使用了[url=https://github.com/tanoku/redcarpet]redcarpet[/url],因为他采用了Ruby wrap C代码,所以性能很不错。但是markdown本身不支持嵌入flash等功能,有时候用户还是需要贴个视频的,所以做了一个扩展支持flash,利用markdown的img标签,先生成一个flash为前缀的地址:
{name:'Flash', key:'F', placeHolder:'![600x450](flash:http://www.youtube.com/v/9I9SkGwJNOA)'}

然后后端用正则表达式转换一下:
class MarkdownExt < Redcarpet
def to_html
super.gsub(/<img src="flash:(.*?)" alt="(\d+).(\d+)">/) do |match|
flash_tag $1, $2, $3
end
end

protected
def flash_tag(url, width, height)
#...
end
end


4. 任务队列
GuruDigger有很多功能需要用到异步的任务队列,比如调用爬虫分析数据,同步到Twitter,发送电子邮件等,我们采用了[url=https://github.com/defunkt/resque]resque[/url],它基于Redis,提供了非常方便的任务队列框架,另外还有完善的维护功能,以同步到Twitter为例子,在需要同步的时候,只需要调用Resque的入队列方法(enqueue),而另外写一个perform方法来处理队列内的数据:
module TwitterUpdater
def self.included(model)
model.class_eval {
attr_accessor :update_twitter

def update_to_twitter(message)
if self.update_twitter.to_i == 1 && user.twitter_access_token.present?
Resque.enqueue(TwitterUpdater, user.id, message)
end
end
}
end

@queue = :twitter_updater

def self.perform(user_id, message)
p "TwitterUpdater processing #{user_id}, #{message}"
user = User.find(user_id)
token, secret = user.twitter_access_token.split(":")
client = TwitterOAuth::Client.new(
:consumer_key => TwitterConfig['consumer_key'], :consumer_secret => TwitterConfig['consumer_secret'],
:token => token, :secret => secret
)

if client.authorized?
client.update(message + " via @GuruDigger")
else
user.update_attributes(:twitter_access_token => nil)
end
end
end


5. 全文搜索
使用了[url=http://outoftime.github.com/sunspot/]sunspot[/url]插件,他后台服务器是solr(基于Java的Lucene),solr对于小规模应用来说安装和配置相当简单,并且有很好的扩展性,对于大数据量的全文搜索,可以使用它的cluster功能,默认支持的中文是单字分词,我们可以使用mmseg分词算法:[url=http://code.google.com/p/mmseg4j/]mmseg4j[/url]。

Sunspot是通过ActiveRecord的create/update/destroy callback来更新/删除索引,只需要在model里面定义需要索引的属性就可以了:

searchable do
text :name
text :introduction
text :address
end


如果想让索引的工作变成异步,还可以使用[url=https://github.com/bdurand/sunspot_index_queue]sunspot_index_queue[/url]这个addon,也可以使用前面提到的Resque来自己扩展一下。

6. 其他用到的杂项gem
A. 客户端校验
使用了[url=https://github.com/bcardarella/client_side_validations]client_side_validations[/url]插件,好处是只需要在model上定义validate rule,就能够被客户端的js重用,不过和纯客户校验的jquery validate相比,不够灵活。

B. Google Map插件 [url=https://github.com/apneadiving/Google-Maps-for-Rails]gmaps4rails[/url]

C. 用户头像gravatar显示插件gravatar-ultimate

D. Tag插件acts-as-taggable-on

E. 评论插件acts_as_commentable_with_threading

F. 支付插件activemerchant

===总结===
迁移框架是个体力活,要保证数据正确,功能一致,同时还要加上一些新功能,不过RoR的框架越来越成熟,各种gem,plugin经过这几年的发展,组合和扩展非常方便,完成一个项目很像搭乐高玩具的感觉。同时期待Rails 3.1在前端的改进(coffeescript sass)能够提高前端的开发效率。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值