首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > Ruby Rails >

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

2012-07-08 
从C#.net到RoR - GuruDigger的的迁移经验分享广告部分,想看技术部分的可以直接跳过 GuruDigger是一

从C#.net到RoR - GuruDigger的的迁移经验分享
===广告部分,想看技术部分的可以直接跳过 ===

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




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




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

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

因为是业余时间做的,前后差不多用了2个月的时间,统计了一下,我累计用了120多个小时
另外一个开发者linjun,因为是第一次接触ruby的关系,包括学习和开发,累计用了200多个小时。

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

1. 用户认证
Rails项目用户认证当然首选devise,短短的几行配置和代码,就可以搞定一切关于注册,登录,忘记密码等一系列用户认证相关功能,再配合omniauth,还可以实现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  endend


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])  endend


3. 文本编辑
因为是面向web开发者的社区,所以文本编辑器方面用了和Github一样的markdown语法,在前端编辑器用的是markitup,在后端markdown render html的功能上,使用了redcarpet,因为他采用了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="从C#net到RoR - GuruDigger的的迁徙经验分享">/) do |match|      flash_tag $1, $2, $3    end  end  protected  def flash_tag(url, width, height)    #...  endend


4. 任务队列
GuruDigger有很多功能需要用到异步的任务队列,比如调用爬虫分析数据,同步到Twitter,发送电子邮件等,我们采用了resque,它基于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  endend


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

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


如果想让索引的工作变成异步,还可以使用sunspot_index_queue这个addon,也可以使用前面提到的Resque来自己扩展一下。

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

B. Google Map插件 gmaps4rails

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)能够提高前端的开发效率。 1 楼 jonathan_zz 2011-07-18   请教一下,去哪里寻找成熟和性能可靠的gem?除了google以外…… 2 楼 njukidreborn 2012-06-05   Rails有twitter bootstrap的gem包,可以用这个来替代jquery

热点排行