Managing routes for multiple models using slugs without prefixes in Laravel.

Updated: Mar 03, 2025

Managing routes for multiple models using slugs without prefixes in Laravel.

In Laravel, managing routes for multiple models using slugs without prefixes can be achieved by following these steps:

  1. Define the URL slug in each model:

First, you need to define a slug attribute in each model that will be used to generate the URL. This attribute should be defined as an accessor and a mutator. The accessor will be used to retrieve the slug value, while the mutator will be used to set the slug value based on the given input.

// app/Models/Post.php

class Post extends Model
{
    // ...

    public function getSlugAttribute()
    {
        return $this->title->slug;
    }

    public function setSlugAttribute($value)
    {
        $this->attributes['slug'] = $value;
        $this->save();
    }
}

// app/Models/Page.php

class Page extends Model
{
    // ...

    public function getSlugAttribute()
    {
        return $this->title->slug;
    }

    public function setSlugAttribute($value)
    {
        $this->attributes['slug'] = $value;
        $this->save();
    }
}
  1. Define the slug method in each model:

Next, you need to define a slug method in each model that will be used to generate the slug value based on the given input. This method should convert the given input to a URL-friendly string and check if the slug already exists in the database.

// app/Models/Post.php

class Post extends Model
{
    // ...

    public function getSlugAttribute()
    {
        return $this->title->slug;
    }

    public function setSlugAttribute($value)
    {
        $this->attributes['slug'] = $value;
        $this->save();
    }

    public function getSlugValueAttribute()
    {
        return $this->title->value;
    }

    public function setSlugValueAttribute($value)
    {
        $this->title->value = $value;
        $this->title->save();
        $this->save();

        return $this->slug;
    }

    public function getSlugMethod()
    {
        return $this->isDirty('slug') ? $this->getSlugValueAttribute() : $this->slug;
    }

    public function getRouteKeyName()
    {
        return 'slug';
    }

    public function getSlug()
    {
        return $this->isDirty('slug') ? $this->getSlugValueAttribute() : $this->fresh()->slug;
    }

    public function getUrlAttribute()
    {
        return route('posts.show', $this->slug);
    }

    public function setTitleAttribute($value)
    {
        $this->attributes['title'] = $value;
        $this->title = Title::firstOrCreate([
            'value' => Str::slug($value),
        ]);

        $this->setSlugValueAttribute($this->title->fresh()->value);
    }

    public function setContentAttribute($value)
    {
        $this->attributes['content'] = $value;
    }

    public function setPublishedAtAttribute($value)
    {
        $this->attributes['published_at'] = $value;
        $this->save();
    }

    public function setCreatedAtAttribute($value)
    {
        $this->attributes['created_at'] = $value;
    }

    public function setUpdatedAtAttribute($value)
    {
        $this->attributes['updated_at'] = $value;
    }

    public function title()
    {
        return $this->belongsTo(Title::class);
    }
}

// app/Models/Page.php

class Page extends Model
{
    // ...

    public function getSlugAttribute()
    {
        return $this->title->slug;
    }

    public function setSlugAttribute($value)
    {
        $this->attributes['slug'] = $value;
        $this->save();
    }

    public function getSlugValueAttribute()
    {
        return $this->title->value;
    }

    public function setSlugValueAttribute($value)
    {
        $this->title->value = $value;
        $this->title->save();
        $this->save();

        return $this->slug;
    }

    public function getSlugMethod()
    {
        return $this->isDirty('slug') ? $this->getSlugValueAttribute() : $this->slug;
    }

    public function getRouteKeyName()
    {
        return 'slug';
    }

    public function getSlug()
    {
        return $this->isDirty('slug') ? $this->getSlugValueAttribute() : $this->fresh()->slug;
    }

    public function getUrlAttribute()
    {
        return route('pages.show', $this->slug);
    }

    public function setTitleAttribute($value)
    {
        $this->attributes['title'] = $value;
        $this->title = Title::firstOrCreate([
            'value' => Str::slug($value),
        ]);

        $this->setSlugValueAttribute($this->title->fresh()->value);
    }

    public function setContentAttribute($value)
    {
        $this->attributes['content'] = $value;
    }

    public function setPublishedAtAttribute($value)
    {
        $this->attributes['published_at'] = $value;
        $this->save();
    }

    public function setCreatedAtAttribute($value)
    {
        $this->attributes['created_at'] = $value;
    }

    public function setUpdatedAtAttribute($value)
    {
        $this->attributes['updated_at'] = $value;
    }

    public function title()
    {
        return $this->belongsTo(Title::class);
    }
}
  1. Define the routes:

Finally, you need to define the routes for each model without prefixes. You can define the routes in the routes/web.php file or in a separate route file.

// routes/web.php

Route::get('/{model}/{slug}', function ($model, $slug) {
    $modelInstance = app()->make($model)->whereSlug($slug)->firstOrFail();

    return view('models.'.$model.'.show', compact('modelInstance'));
})->where(['model' => ['Post', 'Page']]);

In this example, the {model} wildcard will match either Post or Page, and the {slug} wildcard will match the slug value for the corresponding model instance.

With these steps, you should be able to manage routes for multiple models using slugs without prefixes in Laravel.