0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

LaravelのEloquentでカラムを更新できなかった凡ミスの話

Last updated at Posted at 2023-11-10

はじめに

タイトルの通り、凡ミスの話なので参考になる方は少ないかもしれませんが、自戒と備忘を兼ねて記事に残しておきます。

何が起こったか

以下のようにLaravelのEloquentを使用してデータのupdateOrCreateを行ったところ、column1だけ更新され、column2が更新されませんでした。

Table1::updateOrCreate([
	'id' => 1
], [
	'column1' => 1,
	'column2' => 2
]);

最初にやった対応(悪い例)

初動でミスってしまったのですが、column2が外部キーだったため、それが影響しているのではないかと考えてしまい、色々調べてみてもわからず(原因じゃないので当然ですね)、以下のようにEloquentを使用せずにクエリビルダで更新するようにしました。

DB::table('table1')->updateOrInsert([
	'id' => 1
], [
	'column1' => 1,
	'column2' => 2
]);

正しい対応

その後、どうしても納得がいかずupdateOrCreateの処理を追っていったところ、以下のコードを発見しました。
察しのいい方は気付いたかもしれませんが、$instance->fill($values)->save();という処理がポイントです。
はい、$fillableにcolumn2の定義が漏れていたというオチでした。

vendor\laravel\framework\src\Illuminate\Database\Eloquent\Builder.php
public function updateOrCreate(array $attributes, array $values = [])
{
    return tap($this->firstOrCreate($attributes, $values), function ($instance) use ($values) {
        if (! $instance->wasRecentlyCreated) {
            $instance->fill($values)->save();
        }
    });
}

というわけで、Modelを以下のように修正してupdateOrCreateが問題なく動くようになりました。

protected $fillable = [
    'column1',
    'column2',
];

おわりに

わかってしまうと間抜けな話なのですが、目星をつけていたのと全然違う原因だったというのは多くの人が経験したことがあるのではないでしょうか。
Eloquentのコードを読むいい機会だったと自分を慰めつつ、以下を教訓に丁寧なコーディングを心がけようと思います。

  • カラムの追加や変更をしたら必ずModelを見直す
  • 安易にクエリビルダに逃げない(Eloquentの制御が効かないので)
  • 闇雲に調べるよりコードを追った方が早いことは稀によくある
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?