繁体   English   中英

我如何进行此查询以更有效地检测多个帐户并与has_many配合使用?

[英]How can I make this query to detect multiple accounts more efficient & play well w/ has_many?

在我的用户模型中,我想搜索一个用户是否有多个帐户(又称“多个”)。

用户进行会话; 会话是定制设置的

  1. creator_id =会话登录的第一个用户的ID,以及
  2. updater_id =会话登录的最后一个用户的ID

(两个列都已索引。)

如果在保存会话时检测到两者不同,则保存该会话以备后代(和此查询)使用,因为这意味着用户以一个用户身份登录,然后以另一个用户身份登录-也就是他们是多用户。 (要捕获递归的基本情况,然后在当前会话上重置creator_id 。)

这是执行此操作的代码:

class Session < ActiveRecord::SessionStore::Session
  attr_accessor :skip_setters

  before_save :set_ip
  before_save :set_user

    def set_user
      return true if self.skip_setters
      # First user on this session
      self.creator_id ||= self.data[:user_id] 
      # Last user on this session
      self.updater_id = self.data[:user_id] if self.data[:user_id] 
      if self.creator_id and self.updater_id and 
       self.creator_id != self.updater_id
        logger.error "MULTI LOGIN: User #{self.creator.login} and \
          #{self.updater.login} from #{self.ip}"

        # Save a copy for later inspection
        backup = Session.new {|dup_session| 
          dup_session.attributes = self.attributes
          # overwrite the session_id so we don't conflict with the 
          # current one & it can't be used to log in
          dup_session.session_id = ActiveSupport::SecureRandom.hex(16)
          dup_session.skip_setters = true
        }
        backup.save

        # Set this session to be single user again.
        # Updater is what the user looks for;
        # creator is the one that's there to trigger this.
        self.creator_id = self.updater_id
      end
    end

  # etc... e.g. log IP
end

以下查询确实有效。

但是,这很丑陋,效率不高,并且无法与Rails的关联方法配合使用。 请记住,会话是一个非常大且经常使用的表,用户几乎相同。

我想将其更改为has_many关联(以便所有关联魔术都起作用); 可能:through => :multi_sessions关联。 它应该抓住多边主义的两个方向,而不仅仅是像现在这样的一个方向。

如何改善呢?

class User < ActiveRecord::Base
 has_many :sessions, :foreign_key => 'updater_id'

 # This association is only unidirectional; it won't catch the reverse case
 # (i.e. someone logged in first as this user and then as the other)
 has_many :multi_sessions, :foreign_key => 'updater_id', 
  :conditions => 'sessions.updater_id != sessions.creator_id',
  :class_name => 'Session'
 has_many :multi_users, :through => :multi_sessions,
  :source => 'creator', :class_name => 'User'

 ...

 # This does catch both, but is pretty ugly :(
 def multis
  # Version 1
  User.find_by_sql "SELECT DISTINCT users.* FROM users \
    INNER JOIN sessions \
      ON (sessions.updater_id = #{self.id} XOR sessions.creator_id = {self.id}) AND \
         (sessions.updater_id = users.id XOR sessions.creator_id = users.id) \
    WHERE users.id !=  #{self.id}"
  # Version 2
  User.find(sessions.find(:all, :conditions => 'creator_id != updater_id', 
    :select => 'DISTINCT creator_id, updater_id').map{|x|
      [x.creator_id, x.updater_id]}.flatten.uniq - [self.id])
 end
end

我认为您要解决的会话重用问题很奇怪。 通过处理日志以检测袜子或具有多个帐户的用户,将IP映射到唯一登录更好得多。 有更可靠,更轻松的方法来解决您的问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM