2つのテーブルのどちらにもupdated_atがあり、Eloquentで発行するSQLをみると
テーブルを明示的に指定できていないので下記のエラーがでている。
単純にSQLを書くとテーブル名
.updated_at
で解消できるが、 Eloquentを使用した際の対処法。
Column 'updated_at' in field list is ambiguous
versionとか
- Laravel 5.5.43
- MySQL 5.7.23
テーブルの作成
default.sql
CREATE TABLE `users` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`email` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`password` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`remember_token` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `users_email_unique` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE `posts` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`user_id` int(10) unsigned NOT NULL,
`title` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`body` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
1. 一時的に自動updated_atを外し手動で現在の時間をいれる
Eloquentはupdate()やsave()を使う際、updated_atに現在の時間をいれてくれますが、一時的にその機能を外す方法。
PostController.php
public function update(Request $request){
$now = Carbon::now();
$update_columns = [
'posts.title' => 'おはようございます',
'posts.body' => '本日も晴天なり',
'posts.updated_at' => $now,
];
$post = new Post();
$post->timestamps = false;
$post->join('users','users.id','=','posts.user_id')
->where('posts.id',$request->id)
->update($update_columns);
}
2. Builder.phpのaddUpdatedAtColumn関数を書き換える
issuesを探していたら開発中の5.8で該当のPR がマージされていたので
これと同じ様に修正する。もちろんこれは自己責任になるので注意。
vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php
protected function addUpdatedAtColumn(array $values)
{
if (! $this->model->usesTimestamps()) {
return $values;
}
// return Arr::add(
// $values, $this->model->getUpdatedAtColumn(),
// $this->model->freshTimestampString()
$column = $this->qualifyColumn($this->model->getUpdatedAtColumn());
return array_merge(
[$column => $this->model->freshTimestampString()],
$values
);
}
3. オブジェクトをインスタンス化してから更新する
私は結局これに落ち着いた。
注意点としてselect()などでカラムを指定しないとidなどの値が上書きされていたので、カラムの制御かエイリアスが必要あり。
PostController.php
public function update(Request $request){
// 取得
$post = new Post();
$post->select('posts.*')
->join('users','users.id','=','posts.user_id')
->where('posts.id',$request->id)
->firstOrFail();
// 更新
$post->title = 'おはようございます';
$post->body = '本日も晴天なり';
$post->save();
}