【问题标题】:How to catch ActiveRecord::RecordNotFound exception during save()?如何在 save() 期间捕获 ActiveRecord::RecordNotFound 异常?
【发布时间】:2011-05-24 19:36:04
【问题描述】:

我的数据库中有一个带有电子邮件列的用户表。我还在电子邮件列上创建了一个唯一索引,以防止两个用户注册同一个电子邮件地址(注意:请不要建议我使用validates_uniqueness_of,因为这是我试图避免的)。

当我运行 RSpec 测试以确保无法插入重复记录时,我看到以下错误:

Failures:
  1) User should not allow duplicate email addresses
     Failure/Error: user2.save.should_not be_true
     ActiveRecord::RecordNotUnique:
       SQLite3::ConstraintException: column email is not unique: INSERT INTO "users" ("email", ... ) VALUES ( ... )
     # ./spec/models/user_spec.rb:26

这很好,因为这意味着我的 UNIQUE 索引确实在工作。问题是,我该如何处理这个异常?我希望能够捕捉到它,然后在模型的错误集合中添加一条合理的消息。

我尝试过 - 未成功 - 在控制器中使用 rescue_from 如下:

rescue_from 'ActiveRecord::RecordNotUnique' do |ex|
    raise 'Email must be unique'
end

Rails API 文档似乎没有建议如何覆盖 save() 方法以添加开始/救援块,所以我的问题是:如何处理正在发生的 ActiveRecord::RecordNotUnique 异常在 save() 期间抛出然后将模型标记为无效并向模型的错误集合添加合理的错误消息?

【问题讨论】:

    标签: ruby-on-rails ruby activerecord


    【解决方案1】:
    class User
    ...
    def save
     super
     rescue 'ActiveRecord::RecordNotUnique' 
       logger.error($!.to_s) # or something like that.
     end
    end
    

    您可以重载模型中的任何操作,只需调用super 来执行继承的方法定义

    Rails API prolly 没有提到它,因为它是 Ruby 的一个特性,而不仅仅是 Rails。

    【讨论】:

    • 当我尝试在模型中使用rescue_from时,我收到错误:未定义的方法'resuce_from'...我们使用的是rails 3.0.7,所以它应该可用。它似乎只在 ApplicationController 中可用,而不是 ActiveRecord。
    • 抱歉,我的复制和粘贴有点懒惰,这只是一个普通的rescue 我会更新我的答案
    • 谢谢。根据您的建议,我提出了类似的建议: def save begin super #invoke superclass save() rescue ActiveRecord::RecordNotUnique #todo: 改进错误消息? errors.add :email, '该邮箱地址已被使用' false end end
    【解决方案2】:

    我遇到了类似的问题。我有一个带有索引的表,该表使用多个字段进行排序

    在 db/migrate

    class CreateDids < ActiveRecord::Migration
      def change
        create_table :dids do |t|
          t.string :lada, null: false, limit: 3
          t.string :pre_did, null: false, limit: 4
          t.string :did, null: false, limit: 7
          t.boolean :uso_interno_ns, default: false, null: false
    
          t.timestamps
          t.integer :lock_version, null: false, default: 0
          t.index [:lada, :pre_did, :did], unique: true
        end
      end
    end
    

    现在,为了验证 models/did.rb 中的独特字段组合,我写道:

      validates :lada, presence: true, length: { within: 1..3 }, numericality: { only_integer: true}
      validates :pre_did, presence: true, length: { within: 1..4 }, numericality: { only_integer: true}
      validates :did, presence: true, length: { within: 4..7 }, numericality: { only_integer: true}
      validate do
        errors.add :base,I18n.t('dids.numero_menor_10') unless 10 == ( self.lada + self.pre_did + self.did ).size if self.lada and self.pre_did and self.did
      end
    

    但是,它没有验证重复的混合字段 (lada+pre_did+did),所以在 models/did.rb 中还写道:

    def save
      begin
        super
      rescue ActiveRecord::RecordNotUnique => e
        errors.add(:base,I18n.t('dids.telefono_duplicado'))
        false
      end
    end
    
    def update( x )
      begin
        super x
      rescue ActiveRecord::RecordNotUnique => e
        errors.add(:base,I18n.t('dids.telefono_duplicado'))
        false
      end
    end
    

    在我的情况下,如果我在救援后不返回 false,这不起作用。

    【讨论】:

      猜你喜欢
      • 2023-03-18
      • 1970-01-01
      • 2018-08-27
      • 2022-01-10
      • 1970-01-01
      • 2011-04-27
      • 1970-01-01
      • 1970-01-01
      • 2013-01-01
      相关资源
      最近更新 更多