Skip to main content
Use this alternative when your application already has a Filament Resource. Keep its existing pages and authorization; merge the relevant methods below rather than replacing your Resource. This is application code, not an automatic relationship() method on the disk uploader. First complete steps 1–5 of the Post gallery recipe: models, policy, filename generator, GalleryRows and GalleryFields. Skip its custom PostGallery page and Blade view. Both integrations use exactly the same field configuration and map originals to related SQL rows. The related gallery adapter can replace the recipe’s GalleryRows implementation when you want package-owned row synchronization and stale-edit detection. Preserve the native page transaction and acceptance hooks described here.

What happens on save?

  1. Filament validates the form and stores temporary uploads.
  2. The page writes the Post’s permitted attributes and related gallery rows inside its database transaction. Gallery fields are not assigned to Post attributes.
  3. Native RecordSaved handling checks the saved references and accepts staged uploads after commit. Unlike a custom save page, these Resource pages do not need a manual completeMediaUploadsAfterSave() call.
  4. Editing hydrates each gallery from its own collection and disk. Query scoping and the Post policy prevent opening another owner’s record.
$hasDatabaseTransactions = true is intentional on both pages. The mapper rejects writes outside a transaction. This does not turn SQL and disk/S3 into one atomic transaction. Keep the original recipe’s reference-aware retention policy and test your queue/encoder settings separately.

1. Add the fields to the Resource

The standalone example includes a minimal table. An existing Resource can keep its table, routes, actions and other attributes. Preserve every application-specific policy and tenant scope when merging the example’s owner condition.
app/Filament/Resources/PostResource.php

2. Save on create

Only title is mass assigned. The authenticated owner comes from the server; submitted user_id or post_id values are not accepted as authority.
app/Filament/Resources/PostResource/Pages/CreatePost.php

3. Restore and save on edit

The edit page exposes only the title and the gallery state needed by its form. It reloads and locks the Post, then checks the policy again before updating it. If you already override these methods, merge this mapping with your existing behavior. Other domain attributes still need their own explicit validated mapping.
app/Filament/Resources/PostResource/Pages/EditPost.php

4. Keep the native list page

app/Filament/Resources/PostResource/Pages/ListPosts.php
Register PostResource::class in the application’s panel if it is not already discovered. Do not register both this example and a second Resource for the same route. The regular Post policy from the base recipe supplies viewAny, create and owner-restricted update; no delete action is offered here.

Verify your integration

Create a Post with files in both galleries, save, reload its edit URL and change its title and gallery order. Check that the related row IDs stay stable and files remain in the correct collection. Try another owner’s record and a forged stored path, then force a save failure and retry. An upload finishing is not proof that the record committed. The package tests execute these actual native Resource create/edit pages against synthetic SQLite records and a local fake disk. They check save/reopen/edit, rollback, ownership scope and accepted upload leases. This is separate from the recording of the custom-page variant. Adapt and test any additional save actions or relationship behavior in your own Resource. For Spatie Media Library, use its native collection persistence instead of this mapper; see the Spatie alternative.
Last modified on October 20, 2026