Error HTTP 500 yang muncul sporadis hanya pada fitur interaktif sering berakar dari pemanggilan prop parsial. Pada aplikasi Laravel yang menggunakan Inertia.js, halaman sering kali berjalan normal saat diakses langsung (initial visit), namun mendadak mengalami crash ketika frontend memicu router.reload({ only: ['...'] }).
Gejala: Initial Visit 200 OK, Partial Reload 500
Saat pengguna memuat halaman untuk pertama kali, Inertia merender komponen bersama props dasar. Prop berat yang dibungkus Inertia::lazy() diabaikan oleh backend demi menghemat waktu respons.
Masalah muncul ketika frontend meminta prop tersebut secara spesifik:
router.reload({ only: ['activities'] });Request ini mengirimkan header HTTP berikut ke backend:
X-Inertia: true
X-Inertia-Partial-Component: Organizations/Show
X-Inertia-Partial-Data: activitiesRespons server langsung berstatus 500 Internal Server Error, memutus alur kerja frontend.
Root Cause: Eloquent Strict Mode dalam Evaluasi Closure
Akar masalah ada pada kombinasi dua fitur: Laravel Strict Mode (Model::preventLazyLoading()) dan evaluasi deferred closure pada Inertia.
Pada initial visit, closure di dalam Inertia::lazy() tidak dieksekusi sama sekali, sehingga query relasi yang belum di-eager-load tidak pernah dipanggil. Ketika partial reload meminta data tersebut, Inertia mengeksekusi closure terkait. Jika model induk tidak memuat relasi tersebut sebelumnya, Eloquent mencoba melakukan lazy load secara dinamis.
Jika mode ketat aktif di AppServiceProvider:
Model::preventLazyLoading(! app()->isProduction());Maka Laravel melempar eksepsi alih-alih mengeksekusi query N+1 otomatis.
Diagnosis: Membaca Stack Trace
Buka berkas storage/logs/laravel.log. Log menunjukkan titik kegagalan secara spesifik:
[2024-03-24 10:14:22] local.ERROR: Attempted to lazy load [activities] on model [App\Models\Organization] but lazy loading is disabled. {"userId":1,"exception":"[object] (Illuminate\\Database\\LazyLoadingViolationException(code: 0): Attempted to lazy load [activities] on model [App\\Models\\Organization] at /app/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:844)"}Stack trace memperlihatkan bahwa pemanggilan relasi terjadi di dalam definisi closure controller saat serialisasi prop berlangsung.
Solusi Kode: Eager Loading dan Isolasi Query
1. Pola Bermasalah
Mengakses relasi langsung dari model instance yang belum memuatnya:
public function show(Organization $organization)
{
return Inertia::render('Organizations/Show', [
'organization' => $organization,
// Crash saat dipanggil partial reload:
'activities' => Inertia::lazy(fn () => $organization->activities),
]);
}2. Perbaikan: Explicit Eager Loading
Gunakan load() pada instance model jika relasi belum dimuat, atau jalankan query langsung melalui builder relasi untuk mencegah over-fetching data induk.
public function show(Organization $organization)
{
return Inertia::render('Organizations/Show', [
'organization' => $organization,
// Solusi: Query langsung via relasi atau gunakan loadMissing()
'activities' => Inertia::lazy(function () use ($organization) {
return $organization->activities()
->with('user:id,name')
->latest()
->limit(20)
->get();
}),
]);
}Catatan: Menjalankan query langsung via
$organization->activities()->get()menghasilkan builder query baru yang bersih. Pendekatan ini lebih optimal daripada mengeksekusi$organization->load('activities')yang memutasi state model pada memori.
Verifikasi: Integration Test dengan assertInertia
Uji skenario partial reload secara eksplisit dalam test suite untuk memastikan relasi tidak melanggar aturan lazy loading.
public function test_partial_reload_evaluates_lazy_prop_safely(): void
{
$organization = Organization::factory()
->hasActivities(3)
->create();
$this->actingAs($user = User::factory()->create())
->get(route('organizations.show', $organization), [
'X-Inertia' => 'true',
'X-Inertia-Partial-Component' => 'Organizations/Show',
'X-Inertia-Partial-Data' => 'activities',
])
->assertOk()
->assertInertia(fn ($page) => $page
->component('Organizations/Show')
->has('activities', 3)
->missing('organization')
);
}Uji coba ini mengonfirmasi dua hal: respons bernilai 200 OK tanpa exception dari model strict mode, dan Inertia memfilter props dengan benar tanpa memuat prop yang tidak diminta.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!