[RoR] Login Engine补丁

针对LoginEngine登录引擎存在的用户信息同步问题,本文介绍了一种解决方案。通过改进session管理方式,确保用户信息实时更新,避免了数据不同步的情况,并保持了性能高效。

Login Engine是非常好用的一个登录engine,不过也有个缺点,它把用户信息缓存在session里。如果用户每次修改完自己的资料,都把session更新的话,自然是不会有什么数据不同步的问题。不过试想这样一种情况:

1、用户A登录;用户A的信息将保存在session[:user]里。
2、管理员操作用户A,修改用户A的资料并保存。
3、用户A刷新页面。

如果显示用户资料是从session[:user]读取的话,显然用户A看到的是老的资料。

正确的做法是管理员修改用户资料以后,把用户session里的内容也更新,当然这个实施起来有些困难,目前看来无法由用户ID获得对应的session。

有朋友说session里不应该缓存用户信息,而应只保存用户ID。这是正确的,这样可以解决上面的问题,不过带来的问题是每次都要从数据库查询。

如果每次刷新页面都从数据库重新读取用户信息,对性能影响是很大的。试想一下用户正在浏览一个论坛的帖子列表,这个页面可能所有用户看起来都是一样的,唯一不一样的地方是上面用户信息的显示。由于大部分内容都一样,可以使用缓存加快浏览速度。不过却由于session里只保存了用户ID,不得不读取数据库来获得用户信息,这样就把速度又拖慢了。

所以应该把用户信息缓存起来,但要保证它能及时更新。方法自己做一个缓存管理器,能根据用户ID得到用户信息,也能随时更新它。

学着ActionController::Caching做了一个UserManager,它可以根据线程配置来自动开关互斥器:
(/vender/plugins/login_engine/lib/login_engine/user_management.rb)

module UserManagement  # :nodoc:
  class UnthreadedUserManager  # :nodoc:
    def initialize  # :nodoc:
       @users   =  {}
    end
    
    def get(user_id)
      
@users [user_id]
    end
    
    def set(user_id
,  user)
      
@users [user_id]  =  user
    end
  end
  
  module ThreadSafety 
# :nodoc:
    def get(user_id)  # :nodoc:
       @mutex . synchronize { super }
    end
    def set(user_id
,  user)  # :nodoc:
       @mutex . synchronize { super }
    end
  end
  
  class UserManager 
<  UnthreadedUserManager
    def initialize
      super
      
if  ActionController :: Base . allow_concurrency
        
@mutex   =  Mutex . new
        UserManager
. send ( : include ,  ThreadSafety)
      end
    end
  end
  
  @
@user_manager   =  UserManagement :: UserManager . new
  
  def set_current_user(user)
    
return  session[ : user_id]  =  nil  if  user . nil ?
    session[
: user_id]  =  user . id
    cache_user(user)
  end
  
  def current_user
    get_user(session[
: user_id])
  end
  
  def cache_user(user)
    
return   if  user . nil ?
    @
@user_manager . set(user . id ,  user)
  end
  
  def get_user(user_id)
    @
@user_manager . get(user_id)
  end
end  

修改(/verdor/plugins/login_engine/lib/login_engine.rb):

# dot.gifdot.gif.
require  'login_engine/user_management '

module LoginEngine
  include UserManagement
   # dot.gif.
end

加入上面加粗的2行。

修改(/verdor/plugins/login_engine/lib/login_engine/authenticated_system.rb),把session[:user]替换为session[:user_id]。

修改(/verdor/plugins/login_engine/app/controllers/user_controller.rb):

  def login
    
return   if  generate_blank
    
@user   =  User . new(params[ : user])
    
if  user  =  User . authenticate(params[ : user][ : login] ,  params[ : user][ : password])
      user
. logged_in_at  =   Time . now
      user
. save
      set_current_user(user)
      flash[
: notice]  =   " Login successful "
      redirect_to_stored_or_default 
: action  =>   ' home '
    
else
      
@login   =  params[ : user][ : login]
      flash
. now[ : warning]  =   ' Login unsuccessful '
    end
  end

  def logout
    set_current_user(nil)
    redirect_to 
: action  =>   ' login '
  end

  def get_user_to_act_on
    
@user   =  current_user
  end

简单测试:

require   ' login_engine '

class ApplicationController 
<  ActionController :: Base
  include LoginEngine
  
  helper 
: user
  model 
: user
    
  before_filter 
: login_required
end

class ShowController  <  ApplicationController
  def show
    render_text  " User name: #{current_user.first_name} "
  end
end

class AdminController  <  ApplicationController
  def edit
    user 
=  User . find(params[ : id])
    user
. update_attributes( : first_name  =>  params[ : name])
    cache_user(user)
    render_text "User name: #{user.first_name}"
  end
end

一个简单的模拟:
1、用户A从IE登录,访问/show/show,将显示用户的名字。
2、管理员从FF登录,访问/show/show,将显示管理员名字。
3、管理员访问/show/show/2?name=hello,其中2是用户A的ID。这将把用户A的名字修改为hello。
4、用户A刷新页面,可以看到显示的用户名字已经发生变化。

以上过程说这个修改已经达到目的。实现这个功能并不难,主要是为了保留Login Engine原有的功能不变。

修改后的代码:
www.cppblog.com/Files/cpunion/login_engine.rar
源码地址: https://pan.quark.cn/s/3916362e5d0a 在C#编程平台下,构建一个曲线编辑器是一项融合了图形用户界面(GUI)构建、数据管理及数学运算的应用开发任务。 接下来将系统性地介绍这个曲线编辑器开发过程中的核心知识点:1. **定制曲线面板展示数据曲线**: - 控件选用:在C#的Windows Forms或WPF框架中,有多种控件可用于曲线呈现,例如PictureBox或用户自定义的UserControl。 通过处理重绘事件,借助Graphics对象执行绘图动作,如运用DrawCurve方法。 - 数据图形化:通过线性或贝塞尔曲线连接数据点,以呈现数据演变态势。 这要求掌握直线与曲线的数学描述,例如两点间的直线公式、三次贝塞尔曲线等。 - 坐标系统与缩放比例:构建X轴和Y轴,设定坐标标记,并开发缩放功能,使用户可察看不同区间内的数据。 2. **在时间轴上配置多个关键帧数据**: - 时间轴构建:开发一个时间轴组件,显示时间单位刻度,并允许用户在特定时间点设置关键帧。 时间可表现为连续形式或离散形式,关键帧对应于时间轴上的标识。 - 关键帧维护:利用数据结构(例如List或Dictionary)保存关键帧,涵盖时间戳和关联值。 需考虑关键帧的添加、移除及调整位置功能。 3. **调整关键帧数据,通过插值方法获得曲线**: - 插值方法:依据关键帧信息,选用插值方法(如线性插值、样条插值,特别是Catmull-Rom样条)生成平滑曲线。 这涉及数学运算,确保曲线在关键帧之间无缝衔接。 - 即时反馈:在编辑关键帧时,即时刷新曲线显示,优化用户体验。 4. **曲线数据的输出**: - 文件类型:挑选适宜的文件格式存储数据,例如XML、JSON或...
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值