Build CRUD App Laravel 12: Complete Step-by-Step Guide - Techvblogs

Build CRUD App Laravel 12: Complete Step-by-Step Guide

Learn to build a complete CRUD app with Laravel 12. Step-by-step guide with code examples, best practices, and security tips for beginners.


Suresh Ramani - Author - Techvblogs
Suresh Ramani
 

1 day ago

TechvBlogs - Google News

Building a CRUD app Laravel 12 is one of the best ways to learn web development fundamentals. CRUD stands for Create, Read, Update, and Delete - the four basic operations you need in most web applications.

In this guide, I’ll walk you through building a complete CRUD Laravel 12 application from scratch. You’ll learn to create a simple blog post management system that handles all CRUD operations.

What is CRUD in Laravel 12?

CRUD represents the four essential database operations:

  • Create: Add new records
  • Read: Display existing records
  • Update: Modify existing records
  • Delete: Remove records

Laravel 12 makes building CRUD applications incredibly simple with its built-in features like Eloquent ORM, Blade templates, and resourceful routes.

Prerequisites

Before we start building our CRUD Laravel 12 app, make sure you have:

  • PHP 8.2 or higher
  • Composer installed
  • Laravel 12 installed
  • MySQL or SQLite database
  • Basic understanding of PHP and HTML

Step 1: Create a New Laravel 12 Project

First, let’s create a fresh Laravel 12 project for our CRUD application:

composer create-project laravel/laravel crud-laravel-12
cd crud-laravel-12

This command creates a new Laravel 12 project specifically for our CRUD app Laravel 12.

Step 2: Set Up Database Configuration

Open your .env file and configure your database settings:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=crud_laravel_12
DB_USERNAME=your_username
DB_PASSWORD=your_password

Create the database named crud_laravel_12 in your MySQL server.

Step 3: Create Migration for Posts Table

Let’s create a migration for our blog posts table. This is essential for any CRUD Laravel 12 application:

php artisan make:migration create_posts_table

Open the migration file in database/migrations/ and add the following structure:

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    public function up()
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->id();
            $table->string('title');
            $table->text('content');
            $table->timestamps();
        });
    }

    public function down()
    {
        Schema::dropIfExists('posts');
    }
};

Run the migration:

php artisan migrate

Step 4: Create the Post Model

Generate a model for our CRUD Laravel 12 application:

php artisan make:model Post

Open app/Models/Post.php and add the fillable fields:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    protected $fillable = [
        'title',
        'content',
    ];
}

Step 5: Create the Posts Controller

Create a resourceful controller that handles all CRUD operations:

php artisan make:controller PostController --resource

Open app/Http/Controllers/PostController.php and implement the CRUD methods:

<?php

namespace App\Http\Controllers;

use App\Models\Post;
use Illuminate\Http\Request;

class PostController extends Controller
{
    // Display all posts (READ)
    public function index()
    {
        $posts = Post::latest()->paginate(10);
        return view('posts.index', compact('posts'));
    }

    // Show form to create new post
    public function create()
    {
        return view('posts.create');
    }

    // Store new post (CREATE)
    public function store(Request $request)
    {
        $request->validate([
            'title' => 'required|max:255',
            'content' => 'required',
        ]);

        Post::create($request->all());

        return redirect()->route('posts.index')
            ->with('success', 'Post created successfully.');
    }

    // Display single post
    public function show(Post $post)
    {
        return view('posts.show', compact('post'));
    }

    // Show form to edit post
    public function edit(Post $post)
    {
        return view('posts.edit', compact('post'));
    }

    // Update existing post (UPDATE)
    public function update(Request $request, Post $post)
    {
        $request->validate([
            'title' => 'required|max:255',
            'content' => 'required',
        ]);

        $post->update($request->all());

        return redirect()->route('posts.index')
            ->with('success', 'Post updated successfully.');
    }

    // Delete post (DELETE)
    public function destroy(Post $post)
    {
        $post->delete();

        return redirect()->route('posts.index')
            ->with('success', 'Post deleted successfully.');
    }
}

Step 6: Set Up Routes

Add resourceful routes to routes/web.php:

<?php

use App\Http\Controllers\PostController;
use Illuminate\Support\Facades\Route;

Route::get('/', function () {
    return redirect()->route('posts.index');
});

Route::resource('posts', PostController::class);

This single line creates all necessary routes for our CRUD Laravel 12 application:

  • GET /posts - List all posts
  • GET /posts/create - Show create form
  • POST /posts - Store new post
  • GET /posts/{post} - Show single post
  • GET /posts/{post}/edit - Show edit form
  • PUT /posts/{post} - Update post
  • DELETE /posts/{post} - Delete post

Step 7: Create Blade Templates

Create Layout Template

First, create a main layout at resources/views/layouts/app.blade.php:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>@yield('title', 'CRUD Laravel 12 App')</title>
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <div class="container mt-5">
        <h1 class="mb-4">Laravel 12 CRUD Application</h1>
        
        @if(session('success'))
            <div class="alert alert-success">
                {{ session('success') }}
            </div>
        @endif

        @yield('content')
    </div>

    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

Create Posts Index View

Create resources/views/posts/index.blade.php:

@extends('layouts.app')

@section('title', 'All Posts - CRUD Laravel 12')

@section('content')
<div class="d-flex justify-content-between align-items-center mb-4">
    <h2>All Posts</h2>
    <a href="{{ route('posts.create') }}" class="btn btn-primary">Create New Post</a>
</div>

@if($posts->count() > 0)
    <div class="row">
        @foreach($posts as $post)
            <div class="col-md-6 mb-4">
                <div class="card">
                    <div class="card-body">
                        <h5 class="card-title">{{ $post->title }}</h5>
                        <p class="card-text">{{ Str::limit($post->content, 100) }}</p>
                        <small class="text-muted">{{ $post->created_at->format('M d, Y') }}</small>
                        
                        <div class="mt-3">
                            <a href="{{ route('posts.show', $post) }}" class="btn btn-info btn-sm">View</a>
                            <a href="{{ route('posts.edit', $post) }}" class="btn btn-warning btn-sm">Edit</a>
                            
                            <form action="{{ route('posts.destroy', $post) }}" method="POST" class="d-inline">
                                @csrf
                                @method('DELETE')
                                <button type="submit" class="btn btn-danger btn-sm" 
                                        onclick="return confirm('Are you sure?')">Delete</button>
                            </form>
                        </div>
                    </div>
                </div>
            </div>
        @endforeach
    </div>

    {{ $posts->links() }}
@else
    <div class="alert alert-info">
        No posts found. <a href="{{ route('posts.create') }}">Create your first post</a>
    </div>
@endif
@endsection

Create Post Creation Form

Create resources/views/posts/create.blade.php:

@extends('layouts.app')

@section('title', 'Create Post - CRUD Laravel 12')

@section('content')
<h2>Create New Post</h2>

<form action="{{ route('posts.store') }}" method="POST">
    @csrf
    
    <div class="mb-3">
        <label for="title" class="form-label">Title</label>
        <input type="text" class="form-control @error('title') is-invalid @enderror" 
               id="title" name="title" value="{{ old('title') }}" required>
        @error('title')
            <div class="invalid-feedback">{{ $message }}</div>
        @enderror
    </div>

    <div class="mb-3">
        <label for="content" class="form-label">Content</label>
        <textarea class="form-control @error('content') is-invalid @enderror" 
                  id="content" name="content" rows="5" required>{{ old('content') }}</textarea>
        @error('content')
            <div class="invalid-feedback">{{ $message }}</div>
        @enderror
    </div>

    <button type="submit" class="btn btn-success">Create Post</button>
    <a href="{{ route('posts.index') }}" class="btn btn-secondary">Cancel</a>
</form>
@endsection

Create Post Edit Form

Create resources/views/posts/edit.blade.php:

@extends('layouts.app')

@section('title', 'Edit Post - CRUD Laravel 12')

@section('content')
<h2>Edit Post</h2>

<form action="{{ route('posts.update', $post) }}" method="POST">
    @csrf
    @method('PUT')
    
    <div class="mb-3">
        <label for="title" class="form-label">Title</label>
        <input type="text" class="form-control @error('title') is-invalid @enderror" 
               id="title" name="title" value="{{ old('title', $post->title) }}" required>
        @error('title')
            <div class="invalid-feedback">{{ $message }}</div>
        @enderror
    </div>

    <div class="mb-3">
        <label for="content" class="form-label">Content</label>
        <textarea class="form-control @error('content') is-invalid @enderror" 
                  id="content" name="content" rows="5" required>{{ old('content', $post->content) }}</textarea>
        @error('content')
            <div class="invalid-feedback">{{ $message }}</div>
        @enderror
    </div>

    <button type="submit" class="btn btn-success">Update Post</button>
    <a href="{{ route('posts.index') }}" class="btn btn-secondary">Cancel</a>
</form>
@endsection

Create Post Detail View

Create resources/views/posts/show.blade.php:

@extends('layouts.app')

@section('title', $post->title . ' - CRUD Laravel 12')

@section('content')
<div class="card">
    <div class="card-body">
        <h1 class="card-title">{{ $post->title }}</h1>
        <small class="text-muted">Published on {{ $post->created_at->format('M d, Y') }}</small>
        
        <div class="mt-4">
            <p class="card-text">{{ $post->content }}</p>
        </div>

        <div class="mt-4">
            <a href="{{ route('posts.edit', $post) }}" class="btn btn-warning">Edit Post</a>
            <a href="{{ route('posts.index') }}" class="btn btn-secondary">Back to Posts</a>
            
            <form action="{{ route('posts.destroy', $post) }}" method="POST" class="d-inline">
                @csrf
                @method('DELETE')
                <button type="submit" class="btn btn-danger" 
                        onclick="return confirm('Are you sure you want to delete this post?')">
                    Delete Post
                </button>
            </form>
        </div>
    </div>
</div>
@endsection

Step 8: Test Your CRUD Laravel 12 Application

Start your Laravel development server:

php artisan serve

Visit http://localhost:8000 to see your CRUD Laravel 12 application in action.

Key Features of Our CRUD Laravel 12 App

1. Create Functionality

Users can add new blog posts through a simple form with title and content fields.

2. Read Functionality

The app displays all posts in a paginated list and shows individual post details.

3. Update Functionality

Users can edit existing posts while preserving the original data in the form.

4. Delete Functionality

Posts can be safely deleted with a confirmation dialog.

Best Practices for CRUD Laravel 12 Applications

1. Form Validation

Always validate user input to ensure data integrity:

$request->validate([
    'title' => 'required|max:255',
    'content' => 'required|min:10',
]);

2. Use Route Model Binding

Laravel automatically resolves model instances based on route parameters:

public function show(Post $post)
{
    return view('posts.show', compact('post'));
}

3. Implement Pagination

For better performance with large datasets:

$posts = Post::latest()->paginate(10);

4. Add CSRF Protection

Always include CSRF tokens in your forms:

@csrf

5. Handle Soft Deletes

For important data, consider using soft deletes instead of permanent deletion.

Common Issues and Solutions

Issue 1: Route Not Found

Solution: Make sure you’ve registered the resource routes correctly:

Route::resource('posts', PostController::class);

Issue 2: Mass Assignment Error

Solution: Add fields to the $fillable array in your model:

protected $fillable = ['title', 'content'];

Issue 3: Validation Errors Not Showing

Solution: Include error display in your Blade templates:

@error('title')
    <div class="invalid-feedback">{{ $message }}</div>
@enderror

Advanced CRUD Features

Adding Search Functionality

Enhance your CRUD Laravel 12 app with search capabilities:

public function index(Request $request)
{
    $query = Post::query();
    
    if ($request->has('search')) {
        $query->where('title', 'like', '%' . $request->search . '%')
              ->orWhere('content', 'like', '%' . $request->search . '%');
    }
    
    $posts = $query->latest()->paginate(10);
    
    return view('posts.index', compact('posts'));
}

Adding Categories

Extend your CRUD app with relationships:

// In Post model
public function category()
{
    return $this->belongsTo(Category::class);
}

Performance Optimization Tips

1. Use Eager Loading

Prevent N+1 query problems:

$posts = Post::with('category')->latest()->paginate(10);

2. Add Database Indexes

For frequently searched columns:

$table->index('title');

3. Cache Frequently Accessed Data

Use Laravel’s caching system for better performance:

$posts = Cache::remember('posts', 3600, function () {
    return Post::latest()->take(10)->get();
});

Security Considerations

1. Authorization

Implement proper user authorization:

public function edit(Post $post)
{
    $this->authorize('update', $post);
    return view('posts.edit', compact('post'));
}

2. Input Sanitization

Always validate and sanitize user input to prevent XSS attacks.

3. Rate Limiting

Protect your CRUD endpoints from abuse:

Route::middleware('throttle:60,1')->group(function () {
    Route::resource('posts', PostController::class);
});

Testing Your CRUD Laravel 12 Application

Feature Tests

Create tests for your CRUD operations:

public function test_user_can_create_post()
{
    $response = $this->post('/posts', [
        'title' => 'Test Post',
        'content' => 'Test content'
    ]);
    
    $response->assertRedirect('/posts');
    $this->assertDatabaseHas('posts', [
        'title' => 'Test Post'
    ]);
}

Conclusion

Building a CRUD app Laravel 12 is straightforward when you understand the basic components: models, controllers, routes, and views. This guide covered everything you need to create a fully functional CRUD application.

The CRUD Laravel 12 approach we’ve used here follows Laravel’s conventions and best practices. You can extend this foundation to build more complex applications by adding features like user authentication, file uploads, and API endpoints.

Remember that successful CRUD Laravel 12 applications focus on user experience, security, and maintainable code. Start with this simple example and gradually add more features as your skills improve.

Next Steps

Now that you’ve built your first CRUD Laravel 12 application, consider:

  1. Adding user authentication with Laravel Breeze
  2. Implementing file upload functionality
  3. Creating API endpoints for mobile apps
  4. Adding real-time features with Laravel Broadcasting
  5. Deploying your app to production

Happy coding with Laravel 12 CRUD applications!

Comments (0)

Comment


Note: All Input Fields are required.