Search code examples
laravellaravel-seeding

Problems with roles in laravel


Please note: I am pretty new to laravel and programming in general.

So I am working on setting up a role system on my laravel project and I followed a tutorial and did eveything the same. My problem is that when registering it should register a new user with role 'User' and that's not happening. Also my database seeding isn't saving any role ID to my users.

My users table migration:

class CreateUsersTable extends Migration
{
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('name');
            $table->string('email')->unique();
            $table->timestamp('email_verified_at')->nullable();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
            $table->unsignedBigInteger('roles_id')->nullable();
            $table->foreign('roles_id')->references('id')->on('roles');
        });
    }

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

My roles table migration:

class CreateRolesTable extends Migration
{
    public function up()
    {
        Schema::create('roles', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('name');
        });
    }

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

My role_user table migration:

class CreateRoleUserTable extends Migration
{

    public function up()
    {
        Schema::create('role_user', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->bigInteger('role_id')->unsigned();
            $table->bigInteger('user_id')->unsigned();
        });
    }

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

My DataBaseSeeder:

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    public function run()
    {
        // Role comes before User seeder here.
        $this->call(RoleTableSeeder::class);
        // User seeder will use the roles above created.
        $this->call(UserTableSeeder::class);
    }
}

RoleTableSeeder

use Illuminate\Database\Seeder;
use App\Role;

class RoleTableSeeder extends Seeder
{
    public function run()
    {
        $role_worker = new Role();
        $role_worker->name = 'worker';
        $role_worker->save();

        $role_admin = new Role();
        $role_admin->name = 'admin';
        $role_admin->save();

        $role_user = new Role();
        $role_user->name = 'user';
        $role_user->save();
    }
}

UserTableSeeder

use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\Hash;
use App\Role;
use App\User;

class UserTableSeeder extends Seeder
{
    public function run()
    {
        $role_worker = Role::where('name', 'worker')->first();
        $role_admin  = Role::where('name', 'admin')->first();
        $role_user  = Role::where('name', 'user')->first();

        $worker = new User();
        $worker->name = 'Worker User';
        $worker->email = '[email protected]';
        $worker->password = Hash::make('password');
        $worker->save();
        $worker->roles()->attach($role_worker);

        $admin = new User();
        $admin->name = 'Admin user';
        $admin->email = '[email protected]';
        $admin->password = Hash::make('password');
        $admin->save();
        $admin->roles()->attach($role_admin);

        $user = new User();
        $user->name = 'Regular user';
        $user->email = '[email protected]';
        $user->password = Hash::make('password');
        $user->save();
        $user->roles()->attach($role_user);
    }
}

Tables after migrating/seeding

So again, my problem is that when registering it should register a new user with role 'User' and that's not happening. Also my database seeding isn't saving any roles_id to my users.


Solution

  • You have a pivot relationship; there is no need to put the roles_id column on your users. Drop these lines from your migration:

    CreateUsersTable

    // $table->unsignedBigInteger('roles_id')->nullable();
    // $table->foreign('roles_id')->references('id')->on('roles');
    

    Everything else looks good; your roles and users tables are being populated, and the pivot is setting the correct values for user_id and role_id. Now, you'd access the user's roles via

    $user->roles
    // Should return a `Collection` of roles, based on the number of records in `role_user`
    

    As a sidenote, you generally don't have an auto-incrementing id on a pivot table, since the data is constantly changing, and you're unlikely to reference role_user.id at any point, so you can also drop this line:

    CreateRoleUserTable

    // $table->bigIncrements('id');
    

    Edit: The bigger issue here is a fundamental lack of understanding on how pivot and many-to-many relationships work (and that's ok, you said you're new to Laravel and programming).

    I believe you're trying to set roles_id on users to role_user.id, but that's fundamentally incorrect. That is not how this type of relationship works. It uses an intermediate table role_user, which has user_id and role_id to link many instances of users to many instances of roles.

    If you were to set roles_id on users, you could only ever have a single role, at which point this would cease to be a many-to-many, and would be a simple link between users and roles, which would render the role_user table completely unnecessary.