从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
can :manage, [Idea, Project, UserEmail], :user_id => user.id
class IdeasController < ApplicationController load_and_authorize_resource def update @idea.update_attributes!(params[:idea]) endend
{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
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
searchable do text :name text :introduction text :address end