blendbyte/nova-attach-many
blendbyte/nova-attach-many provides a Laravel Nova field for managing many-to-many relationships: search and select multiple related records from a modal, attach or detach them, and keep resource forms clean and efficient. Ideal for BelongsToMany fields in Nova.
Install into a Laravel Nova 5 application and pin the patch that fixes filter resolution:
composer require blendbyte/nova-attach-many:^2.0.1
Nova auto-discovers the field, so there is no service provider to register. Before writing resource code, open src/AttachMany.php on the exact installed version and confirm two things: the namespace (this is a fork — expect Blendbyte\NovaAttachMany\AttachMany, not the upstream Dillingham\...) and the fluent methods actually present. Fork APIs drift from the inherited README; five minutes here prevents a BadMethodCallException or a Class not found halfway through a resource.
First use case: a Team resource with a belongsToMany users relationship, where admins should bulk-attach users from the detail page rather than editing each User record:
use Blendbyte\NovaAttachMany\AttachMany;
public function fields(Request $request)
{
return [
ID::make()->sortable(),
Text::make('Name'),
AttachMany::make('Users'), // resolves the `users` BelongsToMany
];
}
Open the Team detail page and verify in this order:
searchableColumns() / searchable().Step 3 is the code path 2.0.1 changed (relatable query filter method resolution), so exercise it deliberately — search, apply any configured filter, and confirm the candidate list and counts agree. If all three behave, the field is wired and everything else is configuration.
Where to look first when something is off, in order: the field class (src/AttachMany.php), the Vue component under resources/js/, the related Nova resource's searchable() and filters, then the 2.0.0 → 2.0.1 diff. Because the fork exists to track Nova 5, diffing against dillingham/nova-attach-many tells you what this fork changed versus what it inherited.
Pass all three constructor arguments when names are ambiguous. Polymorphic pivots, two relationships to the same model, or a label that doesn't match the relation all break implicit resolution. Be explicit:
AttachMany::make('Members', 'users', User::class)
Scope the candidate list on the relationship, not the field. A constrained relation — wherePivot, a scoped relation, or a global scope — propagates into AttachMany's query. This is the pattern that composes cleanly on 2.0.1, where scoped relations combine correctly with the related resource's filter methods:
// Team.php
public function activeUsers(): BelongsToMany
{
return $this->users()->where('users.active', true);
}
// Team resource
AttachMany::make('Active Users', 'activeUsers', User::class)
Tenant, role, and ownership scoping belongs here. Keep it inside code you own rather than reaching into the package.
Gate attach/detach with Nova policies on the related resource. Define attachUser / detachUser, or the generic attach / detach. Prefer hiding the actions for read-only admins over conditionally removing the field — you keep the preview and counts visible while removing the capability.
Use counts for large relationships, preview sparingly. On resources with hundreds of attachable records:
AttachMany::make('Users')
->showCounts()
->showPreview(),
Confirm both method names exist in src/AttachMany.php before shipping — they are upstream conventions, not a fork guarantee. showCounts() alone is the safer default; preview loads related models and can N+1.
Coexist with the native field, split by view. A common layout is AttachMany on the detail page for deliberate bulk work and the stock BelongsToMany field on the index for quick inline toggling. Both can sit on the same relationship — just scope them (->onlyOnDetail() / ->onlyOnIndex()) so operators never see two competing UIs for one pivot.
Keep validation on the related resource. Attach performs a sync-style operation, so wire validation rules and the narrowed searchable query on the related resource and let AttachMany enforce eligibility against that builder. Don't duplicate the same rules inside the field; they will drift.
Decide notification behaviour once. The package emits notifications after attach/detach. If you also run your own toast layer or rely on Nova's ActionExecuted toasts, settle early whether to keep, suppress, or standardise — and centralise that in a NovaServiceProvider helper rather than repeating the decision per field.
Treat it as relationship management, not data entry. It is at its best when the pivot carries no extra attributes. The moment the pivot holds roles, quantities, dates, or anything an operator must set, drop back to a dedicated pivot resource or a Nova action. AttachMany creates the pivot row; it is not a pivot editor.
Smoke-test the attach flow. One Dusk test or a feature test hitting the attach endpoint that attaches a single record is enough to make a Nova minor bump fail loudly instead of silently breaking the admin panel.
Upgrade 2.0.0 → 2.0.1 deliberately. The patch changes how relatable query filter methods are located. No API change, but any resource with a non-trivial searchable() (joins, whereHas, global scopes) may return a different candidate list after the bump. Diff candidate sets before and after on every scoped relationship; don't assume "patch release, no behaviour change."
You are the QA department. 12 stars, zero dependents, fork lineage. Pin exactly (^2.0.1), keep the smoke test, and watch the repo. MIT means vendoring or forking is a viable fallback — budget for the possibility that you inherit this code.
Nova 5 only. On Nova 4 use upstream dillingham/nova-attach-many. Never mix both in one codebase — namespace collisions and asset-publishing conflicts follow.
Read the source before adopting the API. showCounts(), showPreview(), and the three-argument constructor are inherited conventions. Verify the namespace and fluent methods in src/AttachMany.php on the version you installed.
BelongsToMany only. HasMany, BelongsTo, and MorphToMany will no-op or fail at runtime. For MorphToMany, test morph-type handling explicitly — forks have historically assumed a single pivot table.
Empty or over-broad candidate lists are a search-configuration problem. Look first at the related resource's searchableColumns() / searchable() and any global scope. On 2.0.0 the same symptom could come from mis-resolved filter methods — reproduce on 2.0.1 before filing an issue.
Pivot attributes are invisible. Attaching inserts the row with no UI for extra pivot columns. Non-nullable pivot fields need a database default or relationship-level handling. This is the most common "why is my pivot data null" trap.
Authorization is silent when absent. No policy method means allowed (Nova's default), not denied. If attach buttons appear for users who shouldn't have them, the policy is missing — that is configuration, not a package bug.
showPreview() can N+1. Eager-load related models on indexQuery / detailQuery for large relationships, or use showCounts() only.
The extension point is the relationship. When search can't express your filter, constrain the relationship itself (wherePivot, scoped relation, global scope) rather than patching the field. The scoped relation flows into AttachMany's query and, on 2.0.1, composes correctly with the related resource's filter methods — keeping your customisation in code you control.
How can I help you explore Laravel packages today?