← Back to Upcase

Fixing a duplicate key violation and the data-disable-processing option!


(Justin Gordon) #1

If you’re using Devise, and you get a ActiveRecord::RecordNotUnique error when a new user is signing up, where do you look?

An ActiveRecord::RecordNotUnique occurred in registrations#create:

PG::UniqueViolation: ERROR: duplicate key value violates unique constraint
"index_users_on_email" DETAIL: Key (email)=(somebody@yahoo.com) already
exists. : INSERT INTO “users” (“address”, “city”, “confirmation_sent_at”,
“confirmation_token”, “created_at”, “default_location_id”, “email”,
“encrypted_password”, “first_name”, “last_name”, “mobile”, “role”, “state”,
“updated_at”, “zip_code”) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11,
$12, $13, $14, $15) RETURNING “id”

It turns out that the cause of this was a user double clicking on the Save button.

I wrote an article on how to fix this issue here: http://www.railsonmaui.com/blog/2014/02/23/simple-form-and-disable-processing-by-default/

Any comments on it would be warmly appreciated!

My favorite part is how I can set a default for all submit buttons using SimpleForm:

SimpleForm Submit Buttons

Even better, this can be done in one place for all SimpleForm submit buttons!

In a file like config/simple_form.rb, place this initialization code:

    SimpleForm::FormBuilder.class_eval do
      def submit_with_override(field, options = {})
        data_disable_with = { disable_with: 'Processing...' }
        options[:data] = data_disable_with.merge(options[:data] || {})
        submit_without_override(field, options)
      end
      alias_method_chain :submit, :override
    end

What the bit of code above does is that it:

  1. Opens up the FormBuilder class to add a method submit_with_override.
  2. Modifies options hash’s :data element, setting a default value for key
    disable_with that will not apply if there’s already a value there, thus
    allowing the default to be overridden by any individual button.
  3. Calls alias_method_chain which makes is so that a call to submit actually
    calls submit_with_override and that method can call
    submit_without_override, which is the original submit method. The pattern
    of naming the methods with_override and without_override is part of the
    alias_method_chain call. Pretty darn cool!