laravel / nova-issues

554 stars 35 forks source link

Submitting a form always shows “There was a problem submitting the form.” #5531

Closed sailingdeveloper closed 1 year ago

sailingdeveloper commented 1 year ago

Steps to reproduce:

  1. Install Nova
  2. Add a resource
  3. In Nova, go to the create form (or any form)
  4. Fill out all the fields
  5. Click on “Create” (or “Create & Add Another”)

What should happen:

  1. Resource is created successfully

What happens instead:

  1. Error is shown “There was a problem submitting the form.”
  2. No API call is executed whatsoever
  3. Nothing is logged to the console.

Already tried:

  1. Updating, even on version 4.24.2 the problem persists
  2. Googling the issue, no results
  3. ChatGPT'ing the issue, no joy
  4. I don’t have any plugins/packages installed for Nova.
  5. I updated the generated app.js file to log the error that it encounters, which is:
TypeError: t.fill is not a function
    at app.js?id=7b1d24fc7a595840acf4b38432b4a376:1:186265
    at e.exports (_arrayLikeKeys.js:32:10)
    at e.exports (isFunction.js:35:1)
    at app.js?id=7b1d24fc7a595840acf4b38432b4a376:1:186248
    at e.exports (_arrayLikeKeys.js:32:10)
    at e.exports (isFunction.js:35:1)
    at DeleteButton.vue:6:34
    at e.exports (luxon.js:88:44)
    at Proxy.createResourceFormData (DeleteButton.vue:6:1)
    at Proxy.createRequest (app.js?id=7b1d24fc7a595840acf4b38432b4a376:1:186103)

Which seems to be here: image

Extra info:

crynobone commented 1 year ago

Sorry, but we are unable to replicate this issue. Our Nova source code is always tested using Dusk tests and the "Step to reproduce" is already covered by our dusk tests without any failure at the moment.

Unable to reproduce the issue, please provide full reproducing repository based on fresh installation as suggested in the bug report template (or you can refer to https://github.com/nova-issues for example)

sailingdeveloper commented 1 year ago

@crynobone I figured out what it was. Aside from an ID::make('ID', 'id') field, I also had ID::make('ULID', 'ulid'). Changint the ULID to a Text fixes it.

In my opinion, if it’s not intended to have multiple ID fields, then it should maybe be thrown as an error server and/or client side. 😄

davidhemphill commented 1 year ago

Updated the documentation to mention only using one ID field per resource since it has a special use/meaning within Nova (navigatioN). If you need multiple to have multiple passed to your forms, you can use a Text field or a Hidden field if it does not need to be editable.

devilslane-com commented 5 months ago

Adding a +1 to this. I have a fresh Nova install with a Resource defining 2 fields (id and username). App debug is set to true. No validation requirements or required rules. This is straight out of the box with the supplied User resource generated using nova:install. It's infuriating, especially when this is a paid product.

Couldn't be any simpler.

    public function fields(NovaRequest $request)
    {
        return [
            ID::make()->sortable(), // uuid string, not auto-inc int
            Text::make('type', 'type')->sortable(), // 5-char string
            Text::make('username', 'username')->sortable(), // slug string
    }

This generates the html:

<form-id-field index="0" errors="[object Object]" resource-id="65e69e6e6d11f880b4084083" resource-name="users" field="[object Object]" via-resource="" via-resource-id="" via-relationship="" shown-via-new-relation-modal="false" form-unique-id="9xx5zfi8hmj" mode="form" show-help-text="true"></form-id-field>

<input type="text" placeholder="type" class="w-full form-control form-input form-control-bordered" id="type-update-user-text-field" dusk="type" maxlength="-1">

<input type="text" placeholder="username" class="w-full form-control form-input form-control-bordered" id="username-update-user-text-field" dusk="username" maxlength="-1">

Pressing either update button:

  1. "There was an problem submitting the form."
  2. No JS errors in the console.
  3. No network activity or server errors.
  4. Form field content is valid. Neither are null or empty.
  5. Nothing in the log.

Brave 1.64.116 Chromium: 123.0.6312.105 Nova 4.33.2

Near-impossible to debug, but it looks to be like a JS validation error or an error being caught/suppressed from the console. Which is weird, because that specific error is generated from a server response when you look in app.js. My suspicion is the error condition occurs before it sends the request somewhere, and the error is being handled in the response-handling promise.

Brave has an info warning, and no network information about blocked requests etc.

A form field element has neither an id nor a name attribute. This might prevent the browser from correctly autofilling the form.

Which is correct. There is no "name" attribute on the HTML form elements generated by Nova.

nova_error

The notable sections:

                    methods: {
                        handleResponseError(e) {
                            void 0 === e.response || 500 == e.response.status ? Nova.error(this.__("There was a problem submitting the form.")) : 422 == e.response.status ? (this.validationErrors = new te.rF(e.response.data.errors), Nova.error(this.__("There was a problem submitting the form."))) : Nova.error(this.__("There was a problem submitting the form.") + ' "' + e.response.statusText + '"')
                        },
                        } catch (e) {
                            500 === e.response?.status && Nova.error(this.__("There was a problem submitting the form."))
                        }
    handleResponseError(error) {
      if (error.response === undefined || error.response.status == 500) {
        Nova.error(this.__('There was a problem submitting the form.'))
      } else if (error.response.status == 422) {
        this.validationErrors = new Errors(error.response.data.errors)
        Nova.error(this.__('There was a problem submitting the form.'))
      } else {
        Nova.error(
          this.__('There was a problem submitting the form.') +
            ' "' +
            error.response.statusText +
            '"'
        )
      }
    },

Just to be clear again on this - there is no network activity at all anywhere.

The fix required here is more helpful error messaging in the JS. Something like this:

[handleResponseError]: "in else condition. Unknown error while attempting to submit form. The returned error message was: [exception message]"

If we add in some debug help within HandlesFormRequests.js and regenerate app.js within Nova's vendor folder (npm install, rename webpack.mis.dist, npm run dev, npm run prod), like this:

    handleResponseError(error) {
      if (error.response === undefined || error.response.status == 500) {
        console.log ("handleResponseError / if")
        console.log (error)
        Nova.error(this.__('There was a problem submitting the form.'))
      } else if (error.response.status == 422) {
        console.log ("handleResponseError / else if 422")
        console.log (error)
        this.validationErrors = new Errors(error.response.data.errors)
        Nova.error(this.__('There was a problem submitting the form.'))
      } else {
        console.log ("handleResponseError / else")
        console.log (error)
        Nova.error(
          this.__('There was a problem submitting the form.') +
            ' "' +
            error.response.statusText +
            '"'
        )
      }
    },

This busts the cache, and suddenly the XHR is visible again in the network tab.

Finally, we get to the error. It's a 500.

{
    "message": "Transaction already in progress",
    "exception": "MongoDB\\Driver\\Exception\\RuntimeException",
    "file": "/var/www/html/vendor/mongodb/mongodb/src/Operation/WithTransaction.php",
    "line": 60,
    "trace": [
        {
            "file": "/var/www/html/vendor/mongodb/mongodb/src/Operation/WithTransaction.php",
            "line": 60,
            "function": "startTransaction",
            "class": "MongoDB\\Driver\\Session",
            "type": "->"
        },
        {
            "file": "/var/www/html/vendor/mongodb/mongodb/src/functions.php",
            "line": 537,
            "function": "execute",
            "class": "MongoDB\\Operation\\WithTransaction",
            "type": "->"
        },
        {
            "file": "/var/www/html/vendor/mongodb/laravel-mongodb/src/Concerns/ManagesTransactions.php",
            "line": 107,
            "function": "MongoDB\\with_transaction"
        },
}

Now, without getting into the "MongoDB isn't supported" discussion, here are the problems:

  1. Axios' XHR isn't showing up in the network tab. The 500 isn't visible.
  2. The error reporting within Nova isn't providing enough detail to diagnose server-side problem.

This isn't a "documentation" error. It's a "this paid product lacks error reporting" problem.

Fix:

  1. Add additional debug in that function which dumps the error so server-side code issues are resolvable without 3hrs of investigation.

... ....

Additional on the Mongo issue for those who might encounter it:

vendor\laravel\nova\src\Http\Controllers\ResourceUpdateController.php

    public function __invoke(UpdateResourceRequest $request)
    {
        $model = $request->findModelQuery()->lockForUpdate()->firstOrFail();

        try {
            [$model, $resource] = DB::connection($model->getConnectionName())->transaction(function () use ($request, $model) {
                // snip

                DB::transaction(function () use ($request, $model) {
                     // PROBLEM IS HERE
                });

            });

        } catch (Throwable $e) {
            optional($this->actionEvent)->delete();
            throw $e;
        }
    }

This is happening because Nova is nesting one transaction inside another, which MongoDB doesn't like. For good reason - it's unnecessary. Mongo supports transactions, as does the Eloquent driver.

To work around it, rewrite a duplicate localised controller for CRUD operations and remove the double transaction. Inside your resource, tell Nova to use your update controller instead.