使用rails 3中的devise和acts_as_tenant的用户的唯一性

时间:2012-07-18 10:03:36

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

我正在使用acts_as_tenant gem来管理多租户,而我正在使用设计来管理用户。

我只为租户设置了用户模型和帐户模型。 我可以针对多个租户创建用户 - 这一切都正常工作除了当我尝试使用相同的电子邮件创建两个用户对不同的租户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为电子邮件专栏添加了一个唯一索引。 这显然不会影响act_as_tenant想要做的事情...... 我会尝试删除索引,看看是否设计了Devise。

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

4 个答案:

答案 0 :(得分:8)

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

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

答案 1 :(得分:0)

我还没有对它进行过测试,但我想知道更改顺序是否有助于act_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

答案 2 :(得分:0)

刚刚遇到这个问题。 Sweam的解决方案非常好。

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

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命令后添加上面的代码。

答案 3 :(得分:0)

我将其解析为:

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