Finally, let's move to the second role: teachers. Let's also enable registration for them. We will have a radio input on the register page to select a role.
Roles: Model and Migrations
First, we must take care of the backend. Let's introduce a role. We will have a Role
Model and add a role relationship to the User
Model. So, first, the Model with Migrations.
php artisan make:model Role -mphp artisan make:migration "add role id to users table"
app/Models/Role.php:
class Role extends Model{ protected $fillable = [ 'name', ];}
database/migrations/xxx_create_roles_table.php:
Schema::create('roles', function (Blueprint $table) { $table->id(); $table->string('name'); $table->timestamps();});
database/migrations/xxx_add_role_id_to_users_table.php:
Schema::table('users', function (Blueprint $table) { $table->foreignId('role_id')->constrained();});
app/Models/User.php:
class User extends Authenticatable{ use HasFactory, Notifiable; protected $fillable = [ 'name', 'email', 'password', 'role_id', ]; // ...}
Now, let's seed student
and teacher
roles.
database/seeders/DatabaseSeeder.php:
use App\Models\Role; class DatabaseSeeder extends Seeder{ public function run(): void { Role::create(['name' => 'student']); Role::create(['name' => 'teacher']); }}
Refresh the migrations with the seed.
php artisan migrate:fresh --seed
Registration Page: Choose Role
Next, let's add a radio input to select a role.
resources/views/auth/register.blade.php:
<x-guest-layout> <form method="POST" action="{{ route('register') }}"> // ... <!-- Role --> <div class="mt-4"> <x-input-label for="role_id" :value="__('Register as:')" /> <label> <input type="radio" name="role_id" value="1" checked /> Student </label> <label class="ml-2"> <input type="radio" name="role_id" value="2" /> Teacher </label> <x-input-error :messages="$errors->get('role_id')" class="mt-2" /> </div> <div class="flex items-center justify-end mt-4"> <a class="underline text-sm text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:focus:ring-offset-gray-800" href="{{ route('login') }}"> {{ __('Already registered?') }} </a> <x-primary-button class="ms-4"> {{ __('Register') }} </x-primary-button> </div> </form></x-guest-layout>
Register Submit: Save Role
Finally, we must save the role to the database.
app/Http/Controllers/Auth/RegisteredUserController.php:
class RegisteredUserController extends Controller{ // ... public function store(Request $request): RedirectResponse { $request->validate([ 'name' => ['required', 'string', 'max:255'], 'email' => ['required', 'string', 'lowercase', 'email', 'max:255', 'unique:'.User::class], 'password' => ['required', 'confirmed', Rules\Password::defaults()], 'role_id' => ['required', 'in:1,2'], ]); $user = User::create([ 'name' => $request->name, 'email' => $request->email, 'password' => Hash::make($request->password), 'role_id' => $request->role_id, ]); event(new Registered($user)); Auth::login($user); return redirect(route('student.timetable', absolute: false)); }}
Notice: for the validation, we use the in
validation rule instead of exists
because we can only register with these two roles. We want users to refrain from registering with an admin role.
After registering with the teacher role in the database, we see that the correct role is set.
But now the teacher is still landing in the Student area? In the next lesson, we will start separating student and teacher areas.
After runing migrations, php artisan command to add role_id to users table was successful (I confirmed this using: php artisan migrate:status ) but when i chek mysql users database, I am unable to find the foreign key of role_id in users table.
I had to start the whole project again to be sure it wasn't my fault. I have also done research online as to why this is happening and also watched your youtube video titled, "Laravel Migrations: Table created but foreign key failed" but no luck
Can you show me the code of your migration file for this?
Should be:
is it justified to create separate table only for 2-10-N roles ? perhaps consts or enum is better ?
Yes! The key aspect when creating a separate table for roles is - flexibility. Sure, const or enum can do similar things, but over teh long run - you never know what will be needed :)