4

我有下面的代碼塊:ActiveRecord的異常不及時搶救

unless User.exist?(...) 
    begin 
    user = User.new(...) 
    # Set more attributes of user 
    user.save! 
    rescue ActiveRecord::RecordInvalid, ActiveRecord::RecordNotUnique => e 
    # Check if that user was created in the meantime 
    user = User.exists?(...) 
    raise e if user.nil? 
    end 
end 

的原因是,因爲你可能已經猜到了,多個進程會調用此方法的同時創建用戶(如果它不已經存在),所以當第一個進入塊並開始初始化新用戶,設置屬性並最終調用save!時,用戶可能已經被創建。 在這種情況下,我想再次檢查用戶是否存在,並且只在異常時纔會引發異常(=如果沒有其他進程在此期間創建它)。

問題是,定期從保存提出ActiveRecord :: RecordInvalid異常!並沒有從營救區域救出。 任何想法?

編輯:

好吧,這很奇怪。我肯定錯過了什麼。我根據Simone的提示,看起來像這樣重構代碼:

unless User.find_by_email(...).present? 
    # Here we know the user does not exist yet 
    user = User.new(...) 
    # Set more attributes of user 
    unless user.save 
    # User could not be saved for some reason, maybe created by another request? 
    raise StandardError, "Could not create user for order #{self.id}." unless User.exists?(:email => ...) 
    end 
end 

現在,我得到以下異常:

ActiveRecord::RecordNotUnique: Mysql::DupEntry: Duplicate entry '[email protected]' for key 'index_users_on_email': INSERT INTO `users` ... 

在那裏說:「除非user.save」行拋出。 這怎麼可能? Rails認爲可以創建用戶,因爲電子郵件是唯一的,但是Mysql唯一索引阻止插入?那有多可能?怎樣才能避免?

回答

3

在這種情況下,您可能希望使用遷移來在用戶表鍵上創建唯一索引,以便數據庫引發錯誤。

此外,不要忘記在您的用戶模型中添加validates_uniqueness_of驗證。

驗證並不總是可以防止重複的數據(兩個併發請求在同一毫秒內寫入的確有最小的機會)。 如果您將validates_uniqueness_of與索引結合使用,則不需要全部代碼。

unless User.exist?(...) 
    begin 
    user = User.new(...) 
    # Set more attributes of user 
    user.save! 
    rescue ActiveRecord::RecordInvalid, ActiveRecord::RecordNotUnique => e 
    # Check if that user was created in the meantime 
    user = User.exists?(...) 
    raise e if user.nil? 
    end 
end 

成爲

user = User.new(...) 
# Set more attributes of user 
if user.save 
    # saved 
else 
    # user.errors will return 
    # the list of errors 
end 
+0

感謝您的回答,Simone!我使用Devise進行身份驗證,因此User模型包含唯一性驗證,並且電子郵件上有唯一索引。我可以重構我的代碼 開始 user.save! 救援... 結束 到 如果user.save 其他 ... 結束 但我更感興趣的是我原來的問題:爲什麼是我原來沒有捕獲的ActiveRecord :: RecordInvalid例外碼? – 2011-01-07 15:51:04