【发布时间】:2012-05-29 19:31:30
【问题描述】:
检查页面上当前在线用户数量的最佳方法是什么?
【问题讨论】:
标签: ruby-on-rails ruby
检查页面上当前在线用户数量的最佳方法是什么?
【问题讨论】:
标签: ruby-on-rails ruby
像 Yuri Barbashow 的 answer 但使用 Redis (nice introdution for Rails):
# config/initializers/redis.rb
$redis_onlines = Redis.new
# it's the simplest way, but i'd recommend:
# $redis_onlines = Redis.new path: "/tmp/redis.sock", db: 15, driver: :hiredis
# => hiredis driver more fast
# => use unix domain socket if it's possible
# => default db is No.0, but it is better to use a specific database
# and No.0 leave for testing-development-and-more-and-more
宝石文件
# Gemfile
gem 'redis'
gem 'hiredis' # optional
# don't forget to run `bundle`
设置为online
# app/controllers/application_controller.rb
after_filter :set_online
# the Rails 4 way is:
# after_action :set_online
private
# set to online
def set_online
if !!current_user
# using separate Redis database
# such as $redis_onlines = Redis.new db: 15
# value not need, only key
$redis_onlines.set( current_user.id, nil, ex: 10*60 )
# 'ex: 10*60' - set time to live - 10 minutes
end
end
在线吗?
# app/models/user.rb
def online?
$redis_onlines.exists( self.id )
end
还有小红利(如果你使用单独的 redis 数据库)
# app/cpntrollers/application_controller.rb
def all_who_are_in_touch
$redis_onlines.keys
# => [ "123", "234", "1", "23" ]
# array of ids
end
设置为online
# app/controllers/application_controller.rb
def set_online
if !!current_user
$redis_onlines.set( "user:#{current_user.id}", nil, ex: 10*60 )
else
$redis_onlines.set( "ip:#{request.remote_ip}", nil, ex: 10*60 )
end
end
在线吗?
# app/models/user.rb
def online?
$redis_onlines.exists( "user:#{self.id}" )
end
所有联系的人:
# app/cpntrollers/application_controller.rb
def all_signed_in_in_touch
ids = []
$redis_onlines.scan_each( match: 'user*' ){|u| ids << u.gsub("user:", "") }
ids
end
def all_anonymous_in_touch
$redis_onlines.scan_each( match: 'ip*' ).to_a.size
end
def all_who_are_in_touch
$redis_onlines.dbsize
end
before_filter 而不是after_filter
# app/controllers/application_controller.rb
before_filter :set_online # before_action for Rails 4
session[:user_id] 是当前用户的 id)# app/controllers/session_controller.rb
before_filter :clear_from_signed_in_touch, only: :destroy
before_filter :clear_from_anonymous_in_touch, only: :create
private
def clear_from_anonymous_in_touch
$redis_onlines.del( "ip:#{request.remote_ip}" )
end
def clear_from_signed_in_touch
$redis_onlines.del( "user:#{session[:user_id]}" )
end
后记:Redis | set | exists | expire | scan | scan_each | redis-rb | hiredis | nice introduction for beginners
【讨论】:
最简单的方法是将 last_online 时间戳添加到您的用户模型中,然后为名为 online_now 的用户定义一个范围
class User < ActiveRecord::Base
def self.online_now
where("last_online > ?", 15.minutes.ago)
end
end
【讨论】: