はじめに
タイトルの通り、凡ミスの話なので参考になる方は少ないかもしれませんが、自戒と備忘を兼ねて記事に残しておきます。
何が起こったか
以下のように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の定義が漏れていたというオチでした。
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の制御が効かないので)
- 闇雲に調べるよりコードを追った方が早いことは稀によくある