Help us understand the problem. What is going on with this article?

Laravelリレーション初心者向け!外部キーがデフォルトでないパターン!!!

foreign_key が <テーブル名>_id でない場合のリレーション

日本語ドキュメントはこちらです!
https://readouble.com/laravel/6.x/ja/eloquent-relationships.html

がッッッ!!!!
わたしは日本語ドキュメント見ても分からない、、ドキュメントのドキュメントがほぢいぃぢいいいい!と思っておりますので同じような方に向けて。
または自分のために忘れぬようメモとして、書きます~~~~。

やりたいこと

image.png

まずは結論

Status.php
class Status extends Model
{
    public function history()
    {
        return $this->belongsTo(History::class, 'post_number');
    }
}
History.php
class History extends Model
{
    public function status()
    {
        return $this->hasOne(Status::class, 'post_number');
    }
}
StatusController.php
namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\Status;

class StatusController extends Controller
{
    public function index()
    {
        $statuses = Status::orderBy('created_at', 'asc')->paginate(10);

        return view('status.index', compact('statuses'));
    }
}
index.blade.php
@foreach ($statuses as $status)
<tr>
 <td>{{ optional($status->history)->post_id }}</td>
</tr>
@endforeach

どっちが belongsTo? とわかりづらい場合は、
まっぴーさんのツイートを参考に!!!!!!!!!!!!!!!!!!!!!!!

https://twitter.com/mpyw/status/1197390766642847744

「常に第2引数が Foreign Key で,第3引数が Local Key です。基本的に Local Key はいじらない限りは "id" となるもので,何かしらテーブル名入ってる方は Foreign Key という覚え方でOK」
image.png

とのことなので、 第2引数が id などの Local Key になっていたら belongsTohasOne が逆 です〜〜!
あと公式ドキュメントにも

return $this->hasOne('App\Phone', 'foreign_key', 'local_key');

と載ってるのですがここ大事みたいです!!!!!
わたしはデータをとりにいくテーブル側が hasOne になる!と思い込んでたので最初下記のようにしていて実際にデータも取得はできていたのですが、これだと、 Local Key が第2引数になってしまい正しい形ではないと!

Status.php ❌
class Status extends Model
{
    public function history()
    {
        return $this->hasOne(History::class, 'id', 'post_number');
    }
}

ドキュメントに沿うと下記が正解なのではと思ったけど何故かデータ取得できず…。

Status.php ❓
class Status extends Model
{
    public function history()
    {
        return $this->hasOne(History::class, 'post_number', 'id');
    }
}

そこで belongsTohasOne を反対にするとちゃんとデータも取得でき正しい書き方になったという結論です。(※まっぴーさんに教えてもらった)
ちなみにもし外部キーがデフォルトの、<テーブル名>_id であれば引き数は必要ないけれど、
histories テーブルに status_id があり、それを外部キーとしてデータを取得したい場合)
今回は違うので引数を割り当てます。

基本的には第3引数が id の形になると思われるんじゃけど、

return $this->belongsTo(History::class, 'post_number', 'id');

命名規則にのっていれば第3引数の id はデフォルトなので省略可能。

return $this->belongsTo(History::class, 'post_number');

無事データが取得できたか確認

\DB::enableQueryLog();

Status::find(1)->history;

dd(\DB::getQueryLog());

取得結果
image.png
bindings0 => 1 の意味は、「1つ目の 1 があてられる」
当てはめると下記になる↓

select * from `statuses` where `statuses`.`id` = 1 limit 1;
select * from `histories` where `histories`.`id` = 18 and `histories`.`deleted_at` is null limit 1;

上記を heidiSQL や A5SQL などにコピペして求めてるレコードが取れているか確認する

とれていればオオオオオオっっっkッッッッッッッッKえい!!!!!!!!!!!!!!!!1

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした