Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rails.js not preventing double submit #208

Closed
scottillogical opened this issue Sep 27, 2011 · 41 comments
Closed

Rails.js not preventing double submit #208

scottillogical opened this issue Sep 27, 2011 · 41 comments

Comments

@scottillogical
Copy link

Using form :remote and jquery-rails (1.0.14)

You can easily double submit on firefox 6 and probably most other browsers.
I worked around by adding code like this

$('#form').live('ajax:beforeSend', function(evt, xhr, settings){
  // prevent double submit
  $(':submit', this).click(function() {
    return false;
  });
});
@jaylevitt
Copy link

+1! I thought it was just me. You can't -always- double-submit on Chrome, but you can sometimes; on Firefox 6/7 for Windows/Mac you can always double-submit.

Fail case available if needed. Happens both at HEAD and 1ebfd86, JQuery 1.6.2.

Thanks for the workaround, @scottschulthess - works great for me!

@JangoSteve
Copy link
Member

When you say double-submit, do you mean that the form is submitting twice when you click submit?

@scottillogical
Copy link
Author

@JangoSteve yes, that's exactly it, so clicking the button fires off two ajax requests very fast, which in my particular case caused the second ajax request to 500

@JangoSteve
Copy link
Member

Oh wow, that's strange. The only time I've seen this behavior was when someone was including the jquery-ujs file twice in their layout. If it's doing that on its own, I'd definitely like to see an example.

@jaylevitt
Copy link

@JangoSteve: We've implemented scottschulthess's workaround, so you can't see the problem on production, but if you e-mail me privately (jay at jay dot fm) I'll give you access to our test system so you can see the bug in action.

@JangoSteve
Copy link
Member

@jaylevitt, please make sure the jquery-ujs file isn't being included or compiled twice in the page, as it really sounds like that is what's happening.

@scottillogical
Copy link
Author

it does not appear as if I am including jquery-ujs twice. i'm sure this is as easy as setting up a demo on heroku or something

@JangoSteve
Copy link
Member

I don't think it's as easy as setting up a demo on heroku. I have several rails 3 apps, including 2 production rails 3.1 apps, using jquery-ujs and I've never seen this problem.

@jaylevitt
Copy link

@JangoSteve: yes, I was including it twice (someone helpfully compiled it into coffeescript)... so you're down to Scott's case now :)

@scottillogical
Copy link
Author

checked twice, i don't have two inclusions (using rails 3 cache => true)...seems like the onus is on me now to show a duplicated case though :)

@JangoSteve
Copy link
Member

@scottschulthess, what do all your javascript_include_tags look like in your layout?

@scottillogical
Copy link
Author

javascript_include_tag 'jquery', 'jquery.expander', 'rails.js', 'fef', 'application', :cache => true

@scottillogical
Copy link
Author

the only javascript tag on my prod app is all.js, so I just opened that up and searched for beforeSend and stuff like that, only one instance... i'll check to see if I can produce a dupe case

@JangoSteve
Copy link
Member

In the production app, also make sure jquery is only being included once, because if that's included twice, it can fire the events twice I think.

@JangoSteve
Copy link
Member

@scottschulthess, have you been able to figure out the problem, so we can close this?

@docunext
Copy link

I have an idea as to why this might happen more that we'd expect. Take this scenario:

Production env has assets digest turned off, rakes precompile assets, which creates application.js in public/assets/. Running in dev mode, the app/assets/javascripts/application.js seperately includes the files in isolated script tags, but also includes the default application.js file, which has the same path as the statically rendered one, which in this case bundles the already included files. I get around this by setting config.assets.prefix to '/devassets' in config/environments/development.rb.

@JangoSteve
Copy link
Member

@docunext, I'm not sure I understand. If development were including the precompiled application.js instead of rendering it from sprockets, then it wouldn't contain all the //= require jquery_ujs, etc. And so as long as your layout just has javascript_include_tag 'application', it would not be including all the separate files. Seems like you'd only ever get one or the other.

@jaylevitt
Copy link

I think Steve's right, although we were in the special case of having switched to CoffeeScript in 3.0, created an application.coffee, and then had that included along with the requires in application.js once we went to 3.1. That may be a common mistake.

Meanwhile, we once again ARE seeing double-clicks become double-submits on our production site, even though we have one copy of JQuery-ujs and we're using Scott's workaround on top of that. Steve, if you'd like to poke around, create a free account on www.tiptap.com and take some surveys offered to you; sometimes, on some browsers, you can click twice on an image and it'll double submit. I'll post a real bug report when I have a failcase, but meanwhile, if you're curious...

@docunext
Copy link

Thanks for responding Steve. Let me try to explain better. In my app, the precompiled application.js file in public/assets/application.js has all the files referred to in app/assets/javascripts/application.js.

Because I was running in development mode, rails was expanding:

 = stylesheet_link_tag :application
 = javascript_include_tag :application

to:

<script src="/assets/jquery.js?body=1" type="text/javascript"></script>
<script src="/assets/jquery_ujs.js?body=1" type="text/javascript"></script>
<script src="/assets/elections.js?body=1" type="text/javascript"></script>
<script src="/assets/jquery-pir.js?body=1" type="text/javascript"></script>
<script src="/assets/regulate.js?body=1" type="text/javascript"></script>
<script src="/assets/application.js?body=1" type="text/javascript"></script>

Because app/assets/javascripts/application.js has this contents:

//= require jquery
//= require jquery_ujs
//= require_tree .
//= require regulate

Its supposed to do that, right?

The resulting HTML head would load the individual files 5 files and serve them dynamically rewritten and parsed from app/assets/javascripts/. The last file, application.js, which would normally be dynamically rewritten and parsed from app/assets/javascripts/application.js and should only include the commented out manifest header, but nothing else. Instead, since Rack or Rails found application.js in public/assets/application.js, it serves that one, but it includes everything that's already been served.

@docunext
Copy link

Note Steve, I don't think that my scenario is a bug in rails-jquery or rails-ujs at all. Its probably a circumstance that should be handled by the rails sprockets department. I wrote up a bit more about this here:

http://www.ruby.code-experiments.com/blog/2011/10/another-gotcha-with-the-rails-31-asset-pipeline-or-why-are-my-jquery-ujs-ajax-requests-triggered-twi.html

@scottillogical
Copy link
Author

I'm using rails 3.0 (but with :cache => true) not 3.1. Haven't had a chance to look into this further yet

@JangoSteve
Copy link
Member

@docunext, I think I understand now. Yeah, I forget where, but I read in the docs somewhere, that your application.js (or .coffee) should contain no code except for the //= require statements. That was probably meant to avoid this exact situation. When I upgraded a few Rails 3.0 apps to 3.1 and enabled the asset pipeline, I renamed my application.js file to base.js, and then created a new application.js with just the require headers.

I'm going to close this issue now, since it does not appear to be a jquery-ujs issue.

@JangoSteve
Copy link
Member

Hey guys, FYI, I just came across this bug ticket in jquery when I was searching the jquery 1.7 changelog. Apparently there was a bug in jquery where hitting the Enter button to submit a form in IE8 caused live('submit') bindings to fire twice. If you're still having this problem, try upgrading to the latest jquery-rails which uses jquery 1.7.

@docunext
Copy link

Thanks JangoSteve.

@ericn7
Copy link

ericn7 commented Jul 22, 2012

I just ran into this issue, and it was caused by having the same name for a file with both .js and .js.coffee extensions (ex - "name.js" and "name.js.coffee"). I renamed the .js file, and the double submission stopped.

@yasirs
Copy link

yasirs commented Aug 3, 2012

I can reproduce the issue in Rails 3.1.1:

Start a new app. Add the controllers and views for some ajax action on a submit button. Click on the button, the action fires once.

Now run rake assets:precompile. Start the server, and click the button. The action fires twice.

I either did something wrong in the previous work-flow or this is a bug. Which one is it?

@gouravtiwari
Copy link

+1 for this issue, I see it in Rails 3.2.9

@calbertts
Copy link

👍 I have the same problem!.. :(

@viktorchukhantsev
Copy link

I have same problem on rails 3.2.8.

@seraphinmiranda
Copy link

+1 Same problem on rails 3.2.8

@indirect
Copy link
Member

indirect commented Dec 7, 2012

For all of you guys having this problem, can you please update to the latest jquery-ujs script (manually or by updating your jquery-rails gem), check again, and then report reproductions steps? Most people (including me) aren't seeing this.

@JangoSteve
Copy link
Member

Agreed. I've seen a lot of people reporting this issue and every time so far it's turned out to be some form of including jquery and/or jquery-ujs twice, even when they swore they weren't (and later came back and say they had after all).

I added some code to help people see when this is the case. But I'm thinking it's not always showing that warning for whatever reason, even when it's still being included twice (see report of this in jquery-rails).

If anyone has any ideas as to what else we could do to help prevent this, I'm all ears. I think a lot of it is being caused by people not fully understanding sprockets and the asset pipeline, and I don't necessarily think they should have to understand it. Maybe the solution is better console output or documentation for when people first install and use jquery-rails.

@yasirs
Copy link

yasirs commented Dec 11, 2012

May be someone should upload a repository containing a toy app that shows this error.

@eyaleizenberg
Copy link

Someone on my team included the jquery-ujs again. Thanks to this post, the problem is solved.

Thanks!

@JangoSteve
Copy link
Member

I've also heard of people having this issue if they're using form.js or validate.js (i.e. jquery-ujs submits the form and so does another library), so make sure neither of those are causing the second submit.

@ThomasHPeterson
Copy link

Hi. I'm new to Rails and recently inherited some code that had this problem. I was able to resolve my problem with the help of this thread, so, thank you.

The code I inherited had a "javascript_include_tag 'application'" line in a views/application/_head.html.haml partial, but also the same line in the layouts that render the partial. When I removed the line from the partial, it was fixed.

@Sprachprofi
Copy link

I have the same issue and used the code at http://stackoverflow.com/questions/3188370/ajax-and-preventing-double-submit to get around it.

@jkaipr
Copy link

jkaipr commented Jul 22, 2014

I also encountered a problem like this - double form submission with a Rails 4 remote form. My problem wasn't caused by double inclusion of jquery_ujs, it was caused by a javascript form validation library - https://github.com/jkaipr/bootstrap-validator-rails. I fixed it in the gem and informed the source code author about it - nghuuphuoc/bootstrapvalidator#319.

If you don't have a double jquery_ujs and are experiencing this issue, I suggest you open up Chrome developer tools and look into the Network tab, there you have a column called Initiator - hovering over it will show you the stacktrace leading to the form submission. You should see two requests to the same URL, one of them initiated by jquery_ujs the other one probably by some other piece of javascript.

Hope this helps somebody.

@cs0511
Copy link

cs0511 commented Apr 14, 2015

HI @jkaipr I probably have the same issue as yours. Could you tell me how you fix it? Many thanks.

@jkaipr
Copy link

jkaipr commented Apr 14, 2015

Hi @cs0511 My problem was caused by using jquery_ujs along with bootstrap-validator nowadays it's called formvalidation. It can also be caused by many other libraries which are somehow tweaking form behaviour. The solution that helped me is described in the link mentioned in my previous comment bootstrap-validator-rails gem. You just have to scroll down to the section Together with Rails remote form.

If you don't use bootstrap-validator aka formvalidation, then you have some other javascript troublemaker in your application. If you know how to use Chrome dev tools, the description of how to find out which piece of code is submitting the form is in my previous comment. If you don't, you'll have to learn it.

You have to open the dev tools before submitting the problematic form. After it was submitted, look into dev tools Network tab and find the submit initiator.

@cs0511
Copy link

cs0511 commented Apr 16, 2015

@jkaipr Thank you very much. You saved me a lot of time. I had the same issue as yours.

Again thanks. 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests