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

Hiiro's avatar
Level 2

error when reply (laravel 8)

when user want to reply on the topic, this appear:

Illuminate\Database\QueryException
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'topic_id' cannot be null (SQL: insert into `replies` (`topic_id`, `content`, `user_id`, `updated_at`, `created_at`) values (?, <div>test</div>, 1, 2022-02-08 04:15:38, 2022-02-08 04:15:38)) 

here is my code :

  • store on RepliesController :
 public function store(CreateReplyRequest $request, Topic $topic)
    {
        $user = auth()->user();
        $user->replies()->create([
            'topic_id' => $topic->topic_id,
            'content' => $request->content
        ]);

        return redirect()->back();
    }

  • on Reply and User model :
 public function replies()
    {
        return $this->hasMany(Reply::class);
    }
  • showing on topic :
<div class="card my-5">
                    <div class="card-header">
                        Reply
                    </div>
                    <div class="card-body">
                        @auth
                        <form action="{{route('replies.store',$topic->slug)}}" method="POST">
                            @csrf
                            <input type="hidden" name="content" id="content">
                            <trix-editor input="content"></trix-editor>

                            <button type="submit" class="btn btn-sm my-2 btn-success">
                                Add Reply
                            </button>
                        </form>
                        @else
                        <a href="{{route('login')}}" class="btn btn-info">Sign in to add a reply</a>
                        @endauth
                    </div>
                </div>
0 likes
31 replies
SilenceBringer's avatar

@hiiro check topic_id is in the list of fillable fields

And I think it should be

            'topic_id' => $topic->id
1 like
Sinnbeck's avatar

Show the route. Sounds like your route model binding is set up wrong

Hiiro's avatar
Level 2

@Sinnbeck

Route::resource('topic/{topic}/replies', 'App\Http\Controllers\RepliesController');
Sinnbeck's avatar

@Hiiro can you check the generated route with php artisan route:list. You are passing the slug. Is the route model binding set up with slug?

And dd inside the method

dd($topic);
Hiiro's avatar
Level 2

@SilenceBringer yes, but also error

SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'topic_id' cannot be null (SQL: insert into `replies` (`topic_id`, `content`, `user_id`, `updated_at`, `created_at`) values (?, <div>test</div>, 1, 2022-02-08 05:11:58, 2022-02-08 05:11:58)) 
Sinnbeck's avatar

@Hiiro what do you mean? Do you get an error? Look at both things I mentioned

Hiiro's avatar
Level 2

@Sinnbeck when i tried that

i also change the route from HOME to TOPIC

PS C:\xampp\htdocs\forumMusik> php artisan route:list

   Error 

  Undefined constant App\Providers\RouteServiceProvider::HOME

  at C:\xampp\htdocs\forumMusik\vendor\laravel\framework\src\Illuminate\Container\Con
    917▕         }
    918▕
    919▕         array_pop($this->buildStack);
    920▕

  2   C:\xampp\htdocs\forumMusik\vendor\laravel\framework\src\Illuminate\Container\Container.php:758
      Illuminate\Container\Container::build("App\Http\Controllers\Auth\ConfirmPasswordController")
Hiiro's avatar
Level 2

@Sinnbeck yes i remove that for change the default route should be to topic not home

Hiiro's avatar
Level 2

so i brought it back and the route :


|        | GET|HEAD  | topic/{topic}/replies/create       | replies.create       | App\Http\Controllers\RepliesController@create      
                    | web                                         |
|        | GET|HEAD  | topic/{topic}/replies/{reply}      | replies.show         | App\Http\Controllers\RepliesController@show        
                    | web                                         |
|        | PUT|PATCH | topic/{topic}/replies/{reply}      | replies.update       | App\Http\Controllers\RepliesController@update      
                    | web                                         |
|        | DELETE    | topic/{topic}/replies/{reply}      | replies.destroy      | App\Http\Controllers\RepliesController@destroy     
                    | web                                         |
|        | GET|HEAD  | topic/{topic}/replies/{reply}/edit | replies.edit         | App\Http\Controllers\RepliesController@edit        
                    | web                                         |
Hiiro's avatar
Level 2

@Sinnbeck

i use this for route model

Route::resource('topic/{topic}/replies', 'App\Http\Controllers\RepliesController');

should i change it by dividing the routes like one for store, one for edit

Snapey's avatar

@Hiiro you are expecting to be given a topic in your controller

You have topic in your url (good)

by default, route model binding will try to find the right topic by its id , but in your form you pass the slug

Is slug a column on your database table?

have you configured route model binding to use slug instead of id ?

Hiiro's avatar
Level 2

@Snapey yes, slug is a column for topic table on my database

how to change route model binding?

Hiiro's avatar
Level 2

@Sinnbeck oh i already set it on my topic model

 public function getRouteKeyName()
    {
        return 'slug';
    }
Sinnbeck's avatar

@Hiiro Good. Now we are back to adding dd($topic); to the the store method and seeing if what it finds.. Please post the result :)

Hiiro's avatar
Level 2

@Sinnbeck this is the result :

App\Models\Topic {#1282 ▼
  #table: "topics"
  #primaryKey: "topicID"
  #fillable: array:6 [▶]
  #connection: "mysql"
  #keyType: "int"
  +incrementing: true
  #with: []
  #withCount: []
  +preventsLazyLoading: false
  #perPage: 15
  +exists: true
  +wasRecentlyCreated: false
  #escapeWhenCastingToString: false
  #attributes: array:9 [▶]
  #original: array:9 [▶]
  #changes: []
  #casts: []
  #classCastCache: []
  #attributeCastCache: []
  #dates: []
  #dateFormat: null
  #appends: []
  #dispatchesEvents: []
  #observables: []
  #relations: []
  #touches: []
  +timestamps: true
  #hidden: []
  #visible: []
  #guarded: array:1 [▶]
}
Sinnbeck's avatar

@Hiiro Ok so its found. Show what is under #attributes: array:9 [▶]

Hiiro's avatar
Level 2

@Sinnbeck

#attributes: array:9 [▼
    "topicID" => 2
    "user_id" => 1
    "genre" => ""
    "title" => "Musik"
    "description" => "<div>Musik ada banyak Genre seperti Pop, Rock, Classic dan Jazz</div>"
    "slug" => "musik"
    "genre_id" => 0
    "created_at" => "2022-02-07 17:54:47"
    "updated_at" => "2022-02-07 17:54:47"
  ]
  #original: array:9 [▼
    "topicID" => 2
    "user_id" => 1
    "genre" => ""
    "title" => "Musik"
    "description" => "<div>Musik ada banyak Genre seperti Pop, Rock, Classic dan Jazz</div>"
    "slug" => "musik"
    "genre_id" => 0
    "created_at" => "2022-02-07 17:54:47"
    "updated_at" => "2022-02-07 17:54:47"
  ]
Sinnbeck's avatar
Sinnbeck
Best Answer
Level 102

@Hiiro I would recommend that you read up on best practice for naming columns in the database.. The primary key should just be id not topicID

Anyways. This would then be the correct way of getting the key

$user->replies()->create([
            'topic_id' => $topic->topicID, //fixed
            'content' => $request->content
        ]);
Hiiro's avatar
Level 2

@Sinnbeck okay i'll keep it in my mind when i creating my next project..

its stored to database, but idk why in my database <div>text</div> still appear

like on my reply table, on content column

<div>terimakasih</div>
Sinnbeck's avatar

@Hiiro Just be aware that most of laravels magic can break if you dont follow its convensions for naming things.

Why there is html code in the content, I cannot say without seeing the content input. Maybe you are using some sort of editor that is adding it?

Hiiro's avatar
Level 2

@Sinnbeck like this : i use trix editor for text-editor

<form action="{{route('replies.store',$topic->slug)}}" method="POST">
                            @csrf
                            <input type="hidden" name="content" id="content">
                            <trix-editor input="content"></trix-editor>

                            <button type="submit" class="btn btn-sm my-2 btn-success">
                                Add Reply
                            </button>
                        </form>
Sinnbeck's avatar

@Hiiro Ah there we go. That explains it. It most likely always wraps its content in a div :)

1 like
Snapey's avatar

@Hiiro no you should concentrate on answering what you are being asked

1 like

Please or to participate in this conversation.