Problem/Motivation
If the same form is on a page multiple times and with different arguments, submitting the second form may accidentally be processed with the first form's arguments. Steps to reproduce:
- Have a simple form that does not use #ajax. The #ajax property will force $form_state['cache'] = TRUE, and inadvertently "fix" the bug.
- Pass in different parameters to the form and call it twice on the same menu path.
- Submit the second form.
- You get the results from the first form's arguments, rather than the second one.
Proposed resolution
Create a consistent hash or indicator that can be used across page requests to identify when the same form has been built multiple times on the same page. Actual solution TBD. But some possibilities include:
- This may be a "form_build_count" based on the order the form was built.
- An automatic "form_args_hash" that is made up of the original arguments to separate the two identical forms.
- A manually-provided indicator to separate if the form needs to be supported on the same page multiple times.
Remaining tasks
Solution to be determined. Test coverage expanded to include this bug.
User interface changes
None.
API changes
TBD
Data model changes
None.
| Comment | File | Size | Author |
|---|---|---|---|
| #31 | 2821852-test_only_should_fail-29.patch | 3.12 KB | spokje |
Comments
Comment #2
quicksketchNote that this issue was spun off from #2819375: Do not make entries in "cache_form" when viewing forms that use #ajax['callback'] (Drupal 7 port), which is a Drupal 7 specific problem that has already been solved in Drupal 8. As for this particular issue, I am not sure if Drupal 8 has this same problem or not.
Comment #3
ckaotikIf just ran into this on a Drupal 8 installation. Was displaying a form in a block multiple times with different arguments (pulled from the block config). Drupal would always submit the first occurence of the form.
As mentioned in the issue description, enabling caching of the form state can be used as a workaround, and once I added this I could successfully submit either form.
Comment #6
hugronaphor commentedI have a similar problem but not identical.
I do use #ajax and only one form is loaded on the page, however when I set() a randomly generated value on form build - on submit callback I get a completely different one.
@ckaotik snipped solved it.
Comment #8
wellsSimilar situation here -- custom form with a configuration option to submit via AJAX or redirect to a specific node after submit. If two instances of the form are loaded on the same page, only the initial form's configuration is used.
E.g. if the first instance is configured with a redirect and the second is configured to use AJAX, the second will throw an error on submit because the submit handler attempts to use the configuration from the first form. In this case, the error thrown is:
Symfony\Component\HttpKernel\Exception\HttpException: The specified #ajax callback is empty or not callable. in Drupal\Core\Form\FormAjaxResponseBuilder->buildResponse() (line 67 of core/lib/Drupal/Core/Form/FormAjaxResponseBuilder.php).@ckaotik's workaround in #3 resolved this situation as well, when added to the custom form's
buildFormmethod.Comment #9
khiminrm commented#3 helped me to fix similar problem with 3 same ajax forms with different arguments.
@ckaotik, thanks!
Comment #10
drupixSame form multiple time on a page, no ajax, same problem... Always the first occurrence of the form was submitted.
#3 fixed my Sunday headache ;-)
Thanks @ckaotik !
Comment #11
izus commentedSame issue experienced here with no ajax at all : same form multiple times in a controller
just added the lines from #3 to my buildForm() method and everything worked fine
Thanks @ckaotik
Comment #12
oknateI ran into a related issue with entity browser: #3036406: Edit button of same type doesn't work..
Entity form of the same type is loaded via ajax link, and the ajax POST data infects the form loaded by ajax, so the form for node 2 loads with post data from form 1.
Comment #13
antonnaviI experienced this issue too. To fix this issue I used alternative way: I added "diversity" to my form ID with code:
Can be used as alternative (to solution from #3) way.
Comment #14
cilefen commentedComment #15
lamp5Thx @ckaotik, you saved my day!
Comment #16
makazimtingwa commented@Antonnavi Peace & blessings to you.... this saved me at 2:00am. For some reason #3 isn't working for me in 8.7.8.
Comment #17
codex42 commented#3 works! Thanks. I used it in buildForm()
Comment #19
introfini commentedI had this problem with an ajax callback, #3 solved it for me. Thanks!
Comment #20
fabiansierra5191 commentedThe workaround #3 works, I'm wondering if this is the proper way to fix this? Could this generate cache issues?
Comment #22
geek-merlinThis is a quite complex issue, and FormBuilder a quite convoluted piece of code now.
So a test that reproduces the issue may help someone(tm) to debug this further.
Note that POST and GET method forms may need different approaches, so having both might help.
Comment #23
jeroentI wrote a test that illustrates the problem.
Comment #25
jonas139 commentedI was having the same issue and #3 did the trick for me.
It's a simple form without any ajax.
Comment #26
mxr576Comment #27
mxr576Comment #28
ayushmishra206 commentedComment #29
ayushmishra206 commentedRerolled for 9.3.x , Please review.
Comment #31
spokjeTag clean-up, also re-uploaded the patch from #29 to make it more clear it's a failing-test-only patch, not a solution.
Currently known workarounds: #3 and #13.
Comment #32
sharique commentedBoth the fixed doesn't help in case of webform, it is being tracked in https://www.drupal.org/project/webform/issues/3215639.
Comment #33
spokjeComment #34
grimreaperHello,
Thanks for the 2 lines comment 3, saved my day!
Comment #38
lubwn commented#3 fixed this issue for me as well. I almost pulled my hair off on this since I did not understand why it sends different form than it should, even when form_id was different. Thanks a lot!
Comment #40
ammaletu commentedThe two lines in #3 indeed fix this issue -- but they also potentially open up a new, horrible bug! We added these lines, and now when more than one guest user opens a page with this form, only one of them can submit the form (whoever is quickest). The rest get a "Integrity constraint violation, duplicate entry for node_field__uuid__value" error. This only happens for guest users, because for them the whole page is cached. As I said, a horrible bug for end-users and hard to spot when testing alone.
Think very hard before simply adding these two lines. Are these forms which are displayed to guest users and do you have the static page cache enabled? Not caching the form and using a unique form ID might be the better solution. We will for now try to simply not cache pages which have these forms. Together with the cache kill switch, the fix from #3 seems to work.
Comment #41
sukr_s commentedThe issue it seems that the block loads the configuration for the first block found and therefore the arguments of the first form are used. However if you check the user input in $form_state, the values sent from the browser are correct. I'm assuming that the arguments are stored in hidden fields. If so, you can check for user input for these values and use them if found, otherwise use from arguments
e.g.
with this approach the submit and validate have the correct values for the argument fields.
Comment #42
johnpitcairn commented#3 has saved my day after an awful lot of thrashing, thanks.
I'm not seeing the bug in #40, but we do not have page_cache enabled. It seems fine with the dynamic page cache.
To consistently target multiple instances of the same form on the page with ajax and #states, I'm passing a unique id into the form build from my block plugin, so no form processing will modify it when the form is rebuilt. I've found the following is needed when generating the id to avoid appending a hash on ajax requests.
Comment #44
rob230 commentedThe lines in #3 are not fixing it for me.