Skip to content
Advertisement

Laravel destroy nested resource

I have a resource name OrganizationEmailDomain

Route::resource('organizations.emaildomains', 'OrganizationEmailDomainController', ['except' => ['show']]);

and able to index it just fine

enter image description here

In that view, when clicking in the three dots there’s the destroy part

<form action="{{ route('organizations.emaildomains.destroy', ['organization' => $id, 'emaildomain' => $email_domain->id]) }}" method="post">
    @csrf
    @method('delete')
    <button type="button" class="dropdown-item" onclick="confirm('{{ __("Are you sure you want to delete this email domain?") }}') ? this.parentElement.submit() : ''">
        {{ __('Delete') }}
    </button>
</form>

If in that index view I echo $email_domains (<?php echo $email_domains;?>) then I get as expected (note that the following was before the images were added, so the records don’t match the images)

[{"id":1,"email_domain":"test.com","organization_id":1,"created_at":"2021-03-02T14:46:50.000000Z","updated_at":"2021-03-02T14:46:56.000000Z"},{"id":2,"email_domain":"gmail.com","organization_id":1,"created_at":null,"updated_at":null}]

When I try to destroy

/**
 * Remove the specified resource from storage.
 *
 * @param  AppOrganizationEmailDomain  $emailDomain
 * @return IlluminateHttpResponse
 */
public function destroy(Organization $organization, OrganizationEmailDomain $emailDomain)
{
    //dd($emailDomain);

    $emailDomain->delete();

    return redirect()->route('organizations.emaildomains.index',$organization->id)->withStatus(__("Organization's email domain successfully deleted."));
}

that dd($emailDomain) returns this

dd($emailDomain);

As langbox states

(…) hasMany relationship (…) so it returns a Collection always

So, inspired in this answer from Dan, just substituted

$emailDomain->delete();

with the following

$org_email = OrganizationEmailDomain::where('id', $organization->org_email_domains->pluck('id'))->delete();

given that in Organization model I have

/**
 * Get the email domains of the organization
 *
 * @return void
 */
public function org_email_domains()
{
    return $this->hasMany(OrganizationEmailDomain::class);
}

What’s the problem here?

It always deletes the record that is in the row above.

For example, let’s delete DDDDDDDDDDDDDDDDDDD

enter image description here

this deleted the first row, AAAAAAAAAAAAAAAAA

enter image description here

If I then try to delete BBBBBBBBBBBBBBB (which now became the first row) it’ll delete just fine.


For reference, here’s the index.blade.php where the form I shared previously is at

<table class="table table-flush"  id="datatable-basic">
    <thead class="thead-light">
        <tr>
            <th scope="col">{{ __('Organization') }}</th>
            <th scope="col">{{ __('Email Domain') }}</th>
            <th scope="col">{{ __('Creation date') }}</th>
            @can('manage-org-emaildomains', AppUser::class)
                <th scope="col"></th>
            @endcan
        </tr>
    </thead>
    <tbody>
        @foreach ($email_domains as $email_domain)
            <tr>
                <td>{{ $organization->name }}</td>
                <td>{{ $email_domain->email_domain }}</td>
                <td>{{ $email_domain->created_at ? $email_domain->created_at->format('d/m/Y H:i') : "NULL" }}</td>
                @can('manage-org-emaildomains', AppUser::class)
                    <td class="text-right">
                        @if (auth()->user()->can('update', $email_domain) || auth()->user()->can('show', $email_domain) || auth()->user()->can('delete', $email_domain))
                            <div class="dropdown">
                                <a class="btn btn-sm btn-icon-only text-light" href="#" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                                    <i class="fas fa-ellipsis-v"></i>
                                </a>
                                <div class="dropdown-menu dropdown-menu-right dropdown-menu-arrow">
                                    @can('show', $email_domain)
                                        <a class="dropdown-item" href="{{ route('organizations.emaildomains.show', ['organization' => $id, 'emaildomain' => $email_domain->id]) }}">{{ __('Show') }}</a>
                                    @endcan
                                    @can('update', $email_domain)
                                        <a class="dropdown-item" href="{{ route('organizations.emaildomains.edit', ['organization' => $id, 'emaildomain' => $email_domain->id]) }}">{{ __('Edit') }}</a>
                                    @endcan
                                    @if (auth()->user()->can('delete', $email_domain))
                                        <form action="{{ route('organizations.emaildomains.destroy', ['organization' => $id, 'emaildomain' => $email_domain->id]) }}" method="post">
                                            @csrf
                                            @method('delete')
                                            <button type="button" class="dropdown-item" onclick="confirm('{{ __("Are you sure you want to delete this email domain?") }}') ? this.parentElement.submit() : ''">
                                                {{ __('Delete') }}
                                            </button>
                                        </form>
                                    @endif
                                </div>
                            </div>
                        @endif
                    </td>
                @endcan
            </tr>
        @endforeach
    </tbody>
</table>

Advertisement

Answer

I’ve changed the route to shallow nesting

Route::resource('organizations.emaildomains', 'OrganizationEmailDomainController', ['except' => ['show']])->shallow();

then the form to

<form action="{{ route('emaildomains.destroy', ['organization' => $id, 'emaildomain' => $email_domain->id]) }}" method="post">
    @csrf
    @method('delete')
    <button type="button" class="dropdown-item" onclick="confirm('{{ __("Are you sure you want to delete this email domain?") }}') ? this.parentElement.submit() : ''">
        {{ __('Delete') }}
    </button>
</form>

and the destroy() to

/**
 * Remove the specified resource from storage.
 *
 * @param  AppOrganizationEmailDomain  $emailDomain
 * @return IlluminateHttpResponse
 */
public function destroy(Request $request, OrganizationEmailDomain $emailDomain)
{
    $path = $request->path();

    $id = substr($path, strrpos($path, '/') + 1);

    $emailDomain = OrganizationEmailDomain::find($id);

    $emailDomain->delete();

    return redirect()->route('organizations.emaildomains.index',$request->query()['organization'])->withStatus(__("Organization's email domain successfully deleted."));
}

and now it works fine.

User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement