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

发布于 2024-11-09 08:33:33 字数 894 浏览 0 评论 0原文

我的数据库中有一个包含电子邮件列的用户表。我还在“电子邮件”列上创建了一个 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() 方法以添加开始/救援块,所以我的问题是:如何我可以处理在 save() 期间引发的 ActiveRecord::RecordNotUnique 异常,然后将模型标记为无效并向模型的错误集合添加合理的错误消息吗?

I've got a Users table with an Email column in my database. I've also created a UNIQUE index on the Email column to prevent two users from registering the same email address (note: please don't suggest that I use validates_uniqueness_of since this is what I'm trying to avoid).

When I run run my RSpec test to make sure that a duplicate record cannot be inserted, I see the following error:

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

This is good because it means that my UNIQUE index is indeed working. The question is, how can I handle this exception? I'd like to be able to catch it, then add a sensible message to the model's errors collection.

I've tried - unsuccessfully - using rescue_from in the controller as follows:

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

The Rails API docs don't appear to suggest how to override the save() method in order to add a begin/rescue block, so my question is this: How can I handle the ActiveRecord::RecordNotUnique exception that is being thrown during save() then mark the model as invalid and add a sensible error message to the model's errors collection?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

烙印 2024-11-16 08:33:33
class User
...
def save
 super
 rescue 'ActiveRecord::RecordNotUnique' 
   logger.error($!.to_s) # or something like that.
 end
end

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

Rails API 很可能没有提及它,因为它是 Ruby 的功能,而不仅仅是 Rails 的功能。

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

You can overload any action in your models and just call super to execute the inherited method definition

The Rails API prolly doesn't mention it because its an feature of Ruby, not just Rails.

踏雪无痕 2024-11-16 08:33:33

我有类似的问题。我有一个带有索引的表,该索引使用多个字段,该表

在 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,这是行不通的。

I had a similar problem. I have a table with an index using several fields up by wich the table is sorted

at 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

Now, to validate a unique mix of fields in models/did.rb I wrote:

  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

But, it did not validate for duplicated mix of fields (lada+pre_did+did), so in models/did.rb also wrote:

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

Now in my case, if I do not return false after rescue, this does not work.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文