Only authenticated users can add items to the database
Now let’s re-implement what we did in the first project but this time we show the dogs list when logged out, but we’ll only allow logged in users to modify the data.
First we create a new migration:
php artisan make:migration create_dogs_table
Open the newly created migration file, in my case database/migrations/2023_05_12_164831_create_dogs_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('dogs', function (Blueprint $table) {
$table->id();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('dogs');
}
};
We just modify the migration a little adding a name for the dog:
Schema::create('dogs', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->timestamps();
});
Save the file, go back to the terminal, run php artisan migrate
Now we scaffold the Dog model:
php artisan make:model Dog
Go to routes/web.php
.
At the top, add
use App\Models\Dog;
then find the /
route:
Route::get('/', function () {
return view('welcome');
});
and change it to this to retrieve the dogs list and pass it to the view, which we label index
:
Route::get('/', function () {
$dogs = Dog::all();
return view('welcome', ['dogs' => $dogs]);
})->name('index');
Now in resources/views/welcome.blade.php
we can loop over the dogs array using @foreach
like this:
<h1 class="pb-2 mb-3 font-bold border-b border-b-gray-300">
Dogs
</h1>
<div>
@foreach ($dogs as $dog)
<li class="flex mb-1">
<span class="flex-1">{{ $dog->name }}</span>
</li>
@endforeach
@auth
<p>Logged in</p>
@endauth
@guest
<p>Not logged in</p>
@endguest
</div>
If you refresh the home you’ll see nothing changed because we don’t have any dog in the list.
We can actually show an “empty state” using @forelse
.
Instead of
@foreach ($dogs as $dog)
<li class="flex mb-1">
<span class="flex-1">{{ $dog->name }}</span>
</li>
@endforeach
use this:
@forelse ($dogs as $dog)
<li class="flex mb-1">
<span class="flex-1">{{ $dog->name }}</span>
</li>
@empty
<p>No dogs yet</p>
@endforelse
We don’t have dogs in the table yet, but you can open the database using TablePlus and insert data using this SQL query:
INSERT INTO "dogs" ("id", "name", "created_at", "updated_at") VALUES
('1', 'Roger', '2023-05-11 09:27:20', '2023-05-11 09:27:20'),
('2', 'Syd', '2023-05-11 09:29:52', '2023-05-11 09:29:52'),
('3', 'Botolo', '2023-05-11 09:29:57', '2023-05-11 09:29:57'),
('4', 'Zoe', '2023-05-11 09:30:12', '2023-05-11 09:30:12');
Now when we’re logged in I want to display the form to add a new dog, and the delete button for each dog in the list.
First, inside the Dog
model class we add the name
to an array named $fillable
:
protected $fillable = ['name'];
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Dog extends Model
{
use HasFactory;
protected $fillable = ['name'];
}
We create a controller named DogController
:
php artisan make:controller DogController
This created the app/Http/Controllers/DogController.php
file:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class DogController extends Controller
{
//
}
Add use
App\Models\Dog;
at the top, and add those 2 methods to the class, create
and delete
, as we did before, but this time both first check that the user is logged in:
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\Auth;
use Illuminate\Http\Request;
use App\Models\Dog;
class DogController extends Controller
{
public function create(Request $request)
{
if (Auth::check()) {
$this->validate($request, [
'name' => 'required',
]);
Dog::create($request->all());
}
return to_route('index');
}
public function delete($id)
{
if (Auth::check()) {
$dog = Dog::find($id);
$dog->delete();
}
return to_route('index');
}
}
Ok now we need a route to add a a new dog, and one to delete a dog. In routes/web.php
, add:
use App\Http\Controllers\DogController;
//...
Route::post(
'/dogs',
[DogController::class, 'create']
)->name('dog.create');
Route::delete(
'/dog/{id}',
[DogController::class, 'delete']
)->name('dog.delete');
Now we can display the buttons to remove dogs in resources/views/welcome.blade.php
:
@forelse ($dogs as $dog)
<li class="flex mb-1">
<span class="flex-1">{{ $dog->name }}</span>
@auth
<form action="{{ route('dog.delete', $dog->id) }}" method="POST">
@csrf
@method('DELETE')
<button type="submit" class="p-1 bg-gray-200 border border-black">Delete</button>
</form>
@endauth
</li>
@empty
<p>No dogs yet</p>
@endforelse
We wrap it into @auth
to make it only visible if logged in.
Try clicking one “delete” button, the corresponding row should disappear.
If logged out, here’s what you see:
Now let’s add the form to add a new dog. Before we used a partial, to see how you can use partials, but now let’s just add it to the welcome
template:
@auth
<form method="post" action="{{ route('dog.create') }}">
@csrf
<h3 class="pb-2 mt-4 mb-3 font-bold border-b border-b-gray-300">Add a new dog</h3>
<div class="flex">
<div class="flex-1">
<label>Name</label>
<input type="text" name="name" id="name" class="p-1 border border-gray-200 ">
</div>
<input type="submit" name="send" value="Submit"
class="p-1 bg-gray-200 border border-black cursor-pointer">
</div>
</form>
@endauth
Here’s the full code for reference:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
@vite('resources/css/app.css')
</head>
<body class="p-4">
@if (Route::has('login'))
<div class="text-right">
@auth
<a href="{{ url('/dashboard') }}" class="">Dashboard</a>
@else
<a href="{{ route('login') }}" class="">Log in</a>
@if (Route::has('register'))
<a href="{{ route('register') }}" class="ml-4">Register</a>
@endif
@endauth
</div>
@endif
<h1 class="pb-2 mb-3 font-bold border-b border-b-gray-300">
Dogs
</h1>
<ul>
@forelse ($dogs as $dog)
<li class="flex mb-1">
<span class="flex-1">{{ $dog->name }}</span>
@auth
<form action="{{ route('dog.delete', $dog->id) }}" method="POST">
@csrf
@method('DELETE')
<button type="submit" class="p-1 bg-gray-200 border border-black">Delete</button>
</form>
@endauth
</li>
@empty
<p>No dogs yet</p>
@endforelse
</ul>
@auth
<form method="post" action="{{ route('dog.create') }}">
@csrf
<h3 class="pb-2 mt-4 mb-3 font-bold border-b border-b-gray-300">Add a new dog</h3>
<div class="flex">
<div class="flex-1">
<label>Name</label>
<input type="text" name="name" id="name" class="p-1 border border-gray-200 ">
</div>
<input type="submit" name="send" value="Submit"
class="p-1 bg-gray-200 border border-black cursor-pointer">
</div>
</form>
@endauth
</body>
</html>
→ I wrote 17 books to help you become a better developer, download them all at $0 cost by joining my newsletter
→ JOIN MY CODING BOOTCAMP, an amazing cohort course that will be a huge step up in your coding career - covering React, Next.js - next edition February 2025