开发者

How to catch ActiveRecord::RecordNotFound exception during save()?

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开发者_C百科 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?


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.


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜