在Devise注册控制器中处理ActiveRecord :: RecordNotUnique

时间:2014-01-13 23:02:54

标签: ruby-on-rails ruby activerecord devise

我的用户表在电子邮件和用户名字段中有唯一索引。偶尔会出现唯一性约束,并抛出ActiveRecord::RecordNotUnique异常。当用户快速连续两次提交注册表单,或者当两个用户同时尝试使用相同的用户名注册时,可能会由于rails唯一性验证中的竞争条件而发生。

当异常是由两个连续的注册请求引起的时候我想签署该用户。否则,当两个用户注册相同用户名的罕见情况打破了唯一性约束时,我想显示通常“采取”错误。

为此我已经覆盖了创建动作:

class RegistrationsController < Devise::RegistrationsController
  def create
    begin
      super
    rescue ActiveRecord::RecordNotUnique
      user = User.find_by_email(params[:user][:email])
      if user.present? && user.valid_password?(params[:user][:password])
        # The credentials are valid for the existing user. We can
        # sign them in.
        sign_in(:user, user)
        respond_with user, :location => after_sign_in_path_for(user)
      else
        # The credentials are invalid.
        # This should only happen if multiple users register with the
        # same email at the same time. Now we can simply attempt to
        # register the user again, knowing it will fail, in order to
        # generate the appropriate error messages.
        super
      end
    end        
  end
end

有没有办法让Devise处理ActiveRecord::RecordNotUnique例外并实现类似于我所做的事情?

2 个答案:

答案 0 :(得分:0)

我有同样的问题。

由于add_index :email, unique => true引发了异常,通过设计添加到您的用户模型(查看迁移)。这会在数据库级别添加唯一性约束,从而覆盖frameowrk验证。

实际上我决定放弃电子邮件索引的唯一性,以便我可以使用rails验证来管理所有内容,但实际上我不知道它是否完全正确,也不知道它是否应该以这种方式工作,因为它是第一个我正在使用STI的设计。

希望它有所帮助。

答案 1 :(得分:-2)

只需在资源模型中添加:validatable即可。最有可能是user.rb。它应该是这样的:

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

确保包含:validatable。否则它不会从数据库中捕获错误。