reverbdotcom / rescue-unique-constraint

Graceful handling for ActiveRecord::RecordNotUnique to turn exceptions into ActiveRecord errors

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

SystemStackError when rescuing two unique constraints.

phallstrom opened this issue · comments

Sadly no fix for you, but if you try and rescue two unique constraints your app will crash with a SystemStackError.

spec/rescue_two_unique_constraints_spec.rb

require 'active_record'
require 'rescue_unique_constraint'

describe RescueUniqueConstraint do
  before do
    ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
    ActiveRecord::Schema.verbose = false
    ActiveRecord::Schema.define(:version => 1) do
      create_table :things do |t|
        t.string :foo
        t.string :bar
      end

      add_index :things, :foo, unique: true, name: "idx_things_on_foo_unique"
      add_index :things, :bar, unique: true, name: "idx_things_on_bar_unique"
    end
  end

  class Thing < ActiveRecord::Base
    rescue_unique_constraint index: "idx_things_on_foo_unique", field: "foo"
    rescue_unique_constraint index: "idx_things_on_bar_unique", field: "bar"
  end

  it "rescues unique constraint violations as activerecord errors" do
    thing = Thing.create(foo: "1", bar: "2")
    dupe = Thing.new(foo: "1", bar: "2")
    expect(dupe.save).to eql false
    expect(dupe.errors[:foo].first).to match /taken/
    expect(dupe.errors[:bar].first).to match /taken/
  end
end

Spec run output

F

Failures:

  1) RescueUniqueConstraint rescues unique constraint violations as activerecord errors
     Failure/Error:
       define_method(:create_or_update_with_rescue) do
         begin
           create_or_update_without_rescue
         rescue ActiveRecord::RecordNotUnique => e
           case e.message
           when /#{index}/  # Postgres
             errors.add(field, :taken)
           when /UNIQUE.*#{field}/ # SQLite
             errors.add(field, :taken)
           else

     SystemStackError:
       stack level too deep
     # ./lib/rescue_unique_constraint.rb:11:in `block in rescue_unique_constraint'

    .... the above line repeats many many many times....

  # ./lib/rescue_unique_constraint.rb:13:in `block in rescue_unique_constraint'
     # .../gems/activerecord-4.2.5/lib/active_record/persistence.rb:120:in `save'
     # .../gems/activerecord-4.2.5/lib/active_record/validations.rb:37:in `save'
     # .../gems/activerecord-4.2.5/lib/active_record/attribute_methods/dirty.rb:21:in `save'
     # .../gems/activerecord-4.2.5/lib/active_record/transactions.rb:286:in `block (2 levels) in save'
     # .../gems/activerecord-4.2.5/lib/active_record/transactions.rb:351:in `block in with_transaction_returning_status'
     # .../gems/activerecord-4.2.5/lib/active_record/connection_adapters/abstract/database_statements.rb:213:in `block in transaction'
     # .../gems/activerecord-4.2.5/lib/active_record/connection_adapters/abstract/transaction.rb:184:in `within_new_transaction'
     # .../gems/activerecord-4.2.5/lib/active_record/connection_adapters/abstract/database_statements.rb:213:in `transaction'
     # .../gems/activerecord-4.2.5/lib/active_record/transactions.rb:220:in `transaction'
     # .../gems/activerecord-4.2.5/lib/active_record/transactions.rb:348:in `with_transaction_returning_status'
     # .../gems/activerecord-4.2.5/lib/active_record/transactions.rb:286:in `block in save'
     # .../gems/activerecord-4.2.5/lib/active_record/transactions.rb:301:in `rollback_active_record_state!'
     # .../gems/activerecord-4.2.5/lib/active_record/transactions.rb:285:in `save'
     # .../gems/activerecord-4.2.5/lib/active_record/persistence.rb:34:in `create'
     # ./spec/rescue_two_unique_constraints_spec.rb:25:in `block (2 levels) in <top (required)>'
Finished in 0.03207 seconds (files took 0.44959 seconds to load)
1 example, 1 failure

Failed examples:

rspec ./spec/rescue_two_unique_constraints_spec.rb:24 # RescueUniqueConstraint rescues unique constraint violations as activerecord errors

Thanks for pointing this out. We'll take a look.

Looks like this was fixed in #3, right?