TLDR
Here’s an easy way to have all your SimpleForm submit buttons default to setting
data-disable-with so that you don’t get errors when users double click on
submit buttons. If you’ve gotten a few ActiveRecord::RecordNotUnique errors
that were hard to reproduce, then here’s your solution, with our without
SimpleForm. Additionally, using data-disable-with provides the user with nice
feedback once a button is clicked.
ActiveRecord::RecordNotUnique Error!
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"
At first, I was concerned that my unique index on my users table is not case insensitive. I started going down the road of converting my normal unique index on users.email to this index:
1
| |
However, I soon figured out that Devise was already always saving email in the
database in lower case via a before_validation hook.
So then I tried to double click the SAVE button, and, BOOM, I got the same error.
data-disable-with=’Processing…’
A little bit of googling quickly revealed some handy rails techniques disabling
a submit button after being clicked, namely the setting of attribute
data-disable-with: “Some Message…” on both links and buttons. This works
nicely to fix the double submit RecordNotUnique error, and it provides some
sweet user feedback upon clicking a button. Here’s an example of a SAVE button.
Immediately after clicking the SAVE button, the button disables and the text changes.
Buttons
Example and API: button_tag
1
| |
Links
Example and API: link_to
1
| |
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:
1 2 3 4 5 6 7 8 | |
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_withthat 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
calls
submit_with_overrideand that method can callsubmit_without_override, which is the originalsubmitmethod. The pattern of naming the methodswith_overrideandwithout_overrideis part of thealias_method_chaincall. Pretty darn cool!
Here’s a sample sign-up form that overrides the default “Processing…” label
when the SAVE button is clicked.
1 2 3 4 5 6 7 | |
Now go and click on some of your submit buttons, and they will all disable and
display “Processing…”. On a remote form that returned js.erb, I had to send
back this line to reset the submit button:
1
| |
References
Stack Overflow Discussions: