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: Simple Form and Disabling Buttons on Submit by Default - Rails on Maui
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:
- Opens up the FormBuilder class to add a method
submit_with_override
. - 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. - Calls alias_method_chain which makes is so that a call to submit actually
callssubmit_with_override
and that method can call
submit_without_override
, which is the originalsubmit
method. The pattern
of naming the methodswith_override
andwithout_override
is part of the
alias_method_chain
call. Pretty darn cool!