Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Kramas's avatar

How to use attach method for an API Laravel project?

Hi evereyone,

My project is an API on Laravel. I've got two tables (users & projects) who have a relationship many to many, so I've a pivot table (user_project). So I would like to assign users to projects by giving the id in the route.

I tried by myself with attach method, it works when I give an id to findOrFail method in the code

ProjectController.php

public function affect(Request $request, Project $project, User $user){
        $pjt= Project::findOrFail(1);
        $pjt->users()->attach($user);
    }

But when I don't want to give an id and i put $project in findOrFail(), I've got an error "BadMethodCallException Method users does not exist" when I'm testing the route. Sorry, I'm only starting in Laravel.

I put my code to you:

ProjectController.php

public function affect(Request $request, Project $project, User $user){
        $pjt= Project::findOrFail($project);
        $pjt->users()->attach($user);
    }

Project.php (Model)

    public function users()
    {
        return $this->belongsToMany(User::class, 'user_project', 'project_id', 'user_id')->select( 'email', 'date_of_birth', 'firstname', 'lastname');
    }

    public function status()
    {
        return $this->belongsTo(Status::class);
    }
}

User.php (Model)

public function projects()
    {
        return $this->belongsToMany(Project::class, 'user_project', 'user_id', 'project_id');
    }

my api route:

api.php

Route::post('projects/{project}/users/{user}', 'ProjectController@affect');

And my migrations table

create_users_table.php

public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->increments('id');
            $table->string('firstname');
            $table->string('lastname');
            $table->string('email')->unique();
            $table->string('password');
            $table->date('date_of_birth');
            $table->rememberToken();
            $table->timestamps();
        });
}

create_projects_table.php

public function up()
    {
        Schema::create('projects', function(Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->integer('creator_id')->default(1);
            $table->foreign('creator_id')->references('id')->on('users')
                ->onDelete('restrict')
                ->onUpdate('restrict');
            $table->integer('status_id')->default(1);
            $table->foreign('status_id')->references('id')->on('status')
                ->onDelete('restrict')
                ->onUpdate('restrict');
            $table->timestamps();
            $table->softDeletes();

        });
    }

create_user_projects_table.php

public function up()
    {
        Schema::create('user_project', function(Blueprint $table) {
            $table->increments('id');
            $table->timestamps();
            $table->integer('user_id')->unsigned();
            $table->integer('project_id')->unsigned();
            $table->foreign('user_id')->references('id')->on('users')
                ->onDelete('restrict')
                ->onUpdate('restrict');
            $table->foreign('project_id')->references('id')->on('projects')
                ->onDelete('restrict')
                ->onUpdate('restrict');
        });
    }

Thank you in advance for your help

0 likes
3 replies
automica's avatar
automica
Best Answer
Level 54

@kramas not answering your question but some suggestions:

  1. convention for join tables is to use tables in alphabetical order so 'user_project' would be 'project_user'.

if you do this, you should be able to replace

$this->belongsToMany(User::class, 'user_project', 'project_id', 'user_id')

with

$this->belongsToMany(User::class)
  1. for here:
public function affect(Request $request, Project $project, User $user){
        $pjt= Project::findOrFail($project);
        $pjt->users()->attach($user);
    }

as you are using Route Model Binding (and passing in the Project $project) you can do the following

public function affect(Request $request, Project $project, User $user)
   {       
        $project->users()->attach($user);
    }

I cant see any specific reason why your attach doesn't work but switching to using Laravel conventions may make it easier to diagnose.

1 like
Snapey's avatar

You are type hinting the project so you should not need the findOrFail at all

public function affect(Request $request, Project $project, User $user)
{
    $project->users()->attach($user);
}

Also, I noticed your select in the relationship. Always make sure you include the primary key (id) in the select otherwise the records cannot be linked up.

1 like
Kramas's avatar

It works, thank you so much for your help !

Please or to participate in this conversation.