【问题标题】:Uniqueness of users with devise and acts_as_tenant in rails 3rails 3中具有设计和acts_as_tenant的用户的唯一性
【发布时间】:2012-07-18 10:03:36
【问题描述】:

我正在使用acts_as_tenant gem 来管理多租户,并且我正在使用 devise 来管理用户。

我只为租户设置了设计用户模型和帐户模型。 我可以针对多个租户创建用户——这一切都很好,除了当我尝试针对不同的租户 ID 创建两个具有相同电子邮件的用户时,我得到一个唯一性错误。 我正在使用描述的 validates_uniqueness_to_tenant 选项。

用户模型

class User < ActiveRecord::Base
  # Include default devise modules. Others available are:
  # :token_authenticatable, :confirmable,
  # :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable

  attr_accessible :email, :password, :password_confirmation, :remember_me

  acts_as_tenant(:account)
  validates_uniqueness_to_tenant :email
end

帐户模型

class Account < ActiveRecord::Base
  attr_accessible :name
end

应用程序控制器

class ApplicationController < ActionController::Base
  set_current_tenant_by_subdomain(:account, :subdomain)
  protect_from_forgery
end

这看起来应该基于acts_as_tenant中的所有文档工作,我是否需要在设计级别覆盖某些东西?

编辑:经过一番摸索和休息后,我相信问题出在,因为默认情况下,Devise 已向电子邮件列添加了唯一索引。 这显然不符合acts_as_tenant 想要做的事情...... 我会尝试删除索引,看看 Devise 是否会呕吐。

编辑 2:好的,现在已经正式放弃了。我对主站点进行了手动身份验证,并且可以与acts_as_tenant 一起正常工作。 我只能假设acts_as_tenant 和Devise 在某个层之间存在一些不兼容——在这个阶段我无法找到它。

【问题讨论】:

    标签: ruby-on-rails-3 devise multi-tenant


    【解决方案1】:

    这样做的唯一方法是从设计中删除可验证模块并运行您自己的验证,如下所示:

    class User < ActiveRecord::Base
      acts_as_tenant :account
      attr_accessible :email, :password, :remember_me
    
      #remove :validatable
      devise :database_authenticatable, :registerable,
        :recoverable, :rememberable, :trackable
    
      #run own validations
      #I've omitted any emailformatting checks for clarity's sake.
      validates :email, 
        presence: true,
        uniqueness: { scope: :account_id, case_sensitive: false }
      validates :password,
        presence: true,
        length: { :in => 6..20 },
        :if => :password_required?
    
    protected
      # copied from validatable module
      def password_required?
        !persisted? || !password.nil? || !password_confirmation.nil?
      end
    
    end
    

    【讨论】:

    • 很好的答案 - 值得注意的是其他人不记得删除设计添加的电子邮件上的唯一索引。
    • 仅供参考:AaT 提供了一个范围验证器:validates_uniqueness_to_tenant :email。电子邮件格式也可以使用validates_format_of :email, with: Devise.email_regexp 轻松完成
    【解决方案2】:

    我尚未对其进行测试,但我想知道更改顺序是否有助于acts_as_tenant 在设计接管之前完成它的工作。

    class User < ActiveRecord::Base
    
      acts_as_tenant(:account)
      validates_uniqueness_to_tenant :email
    
      # Include default devise modules. Others available are:
      # :token_authenticatable, :confirmable,
      # :lockable, :timeoutable and :omniauthable
      devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable
    
      attr_accessible :email, :password, :password_confirmation, :remember_me
    
    end
    

    【讨论】:

    • 听起来你正在使用设计索引。如果有任何帮助,在我的系统中,我允许用户绑定到多个租户,然后让他们能够切换当前租户。这可能无法满足您的特定需求。
    【解决方案3】:

    刚刚遇到这个问题。 Swam 的解决方案很不错。

    但我更喜欢不覆盖默认行为。所以我想出了这个解决方案:

    validate :remove_old_email_validation_error
    validates_uniqueness_of :email, :allow_blank => true, :if => :email_changed?, :scope => [:account_id]
    
    private
    
    def remove_old_email_validation_error
      errors.delete(:email)
    end
    

    我们删除了电子邮件的默认验证错误,因此忽略了验证检查,我们再次进行了自己的验证。 我添加的是来自 Validatable 模块,但我已经添加了:scope

    保持秩序很重要。在devise 命令后添加上述代码。

    【讨论】:

      【解决方案4】:

      我把它解决为:

      validate :remove_old_uniquess_email_error

      private
      
        def remove_old_uniquess_email_error
         errors.delete(:email) if self.company_id.nil? && errors[:email].present? && errors[:email] == ["already taken"]
        end
      

      【讨论】:

        猜你喜欢
        • 2019-12-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-10-21
        相关资源
        最近更新 更多