如何在save()期间捕获ActiveRecord :: RecordNotFound异常?

时间:2011-05-24 19:36:04

标签: ruby-on-rails ruby activerecord

我的数据库中有一个带有电子邮件列的Users表。我还在电子邮件列上创建了一个UNIQUE索引,以防止两个用户注册相同的电子邮件地址(注意:请不要建议我使用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()期间抛出然后将模型标记为无效并向模型的错误集合添加合理的错误消息?

2 个答案:

答案 0 :(得分:3)

class User
...
def save
 super
 rescue 'ActiveRecord::RecordNotUnique' 
   logger.error($!.to_s) # or something like that.
 end
end

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

Rails API并未提及它,因为它是Ruby的一个特性,而不仅仅是Rails。

答案 1 :(得分:0)

我有类似的问题。我有一个带有索引的表,使用了几个字段,表格已经分类

在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 ,这不起作用。