【学習】セッションの落とし穴！？PerlでIDから名前を取得するまでの道のり

## はじめに
どんな言語でも・フレームワークでもキャッチアップは同じなのかな。と思い、とあるきっかけでPerlを知り、「せっかくならもう少し理解を深めたい」と思っているわーちゃんです。

今回はある問題を解消したいと思い、実装までの流れを記録したいと思います。

👇前回までの実装内容は下記記事になります

https://qiita.com/wa-chan222/items/5794b40c458e9d943f3c


## 問題とは(どんな風にしたいのか)

前回からの継続で職業と飲み物について、memberテーブルで「職業id」と「飲み物id」として管理できるようにしています。

👇入力内容確認ページで「職業」「飲み物」がid表示になっています。
```tx
<div class="alert alert-light border mt-4" style="padding: 15px; border-radius: 10px;">
    <p><strong>名前:</strong> <: $name :></p>
    <p><strong>誕生日:</strong> <: $birthdate :></p>
    <p><strong>職業:</strong> <: $occupation_id :></p>
    <p><strong>飲み物:</strong> <: $drink_id :></p>
    <p><strong>備考:</strong> <: $remarks :></p>
</div>
```

**このid表示（サイトでは数字の「1」や「3」といったような形で表示されている状態）を名前（水など）で表示できるようにしたい**、ので確認ページを下記のように変更しておきます。
```
<div class="alert alert-light border mt-4" style="padding: 15px; border-radius: 10px;">
    <p><strong>名前:</strong> <: $name :></p>
    <p><strong>誕生日:</strong> <: $birthdate :></p>
    <p><strong>職業:</strong> <: $occupation_name :></p>
    <p><strong>よく飲むお酒:</strong> <: $drink_name :></p>
    <p><strong>備考:</strong> <: $remarks :></p>
</div>
```

ではここから、バック側？の処理をどうすればいいのか、間違いもはさんで進めていきます

## 間違いから

```
# 確認ページへの遷移
post '/confirm' => sub {
    my ($c) = @_;
    my $remarks = $c->req->param('remarks') // '';  # undefだった場合、代わりに ''（空文字）を入れる

    $c->session->set('remarks' => $remarks);

    # occupation_id に対応する職業名を取得
    my $occupation_name = $c->dbh->selectrow_array(
        "SELECT name FROM occupation WHERE id = ?", undef, $occupation_id
    );

    # drink_id に対応する飲み物名を取得
    my $drink_name = $c->dbh->selectrow_array(
        "SELECT name FROM drink WHERE id = ?", undef, $drink_id
    );

    return $c->render('confirm.tx', {
        name       => $c->session->get('name'),
        birthdate     => $c->session->get('birthdate'),
        occupation_name => $c->session->get('occupation_name'),
        drink_name      => $c->session->get('drink_name'),
        remarks    => $remarks,
    });
};
```

はじめにこのように修正しました。
ですがこれでサーバーを再起動しようとしたら見事にエラーとなりました😭
さて、何がいけないのか…。


#### まず**確認ページに遷移する前のページ**で下記のようなコードで処理をしていました。
```perl
post '/question/1' => sub {
    # 省略
    my $occupation_id = $c->req->param('occupation_id');
    $c->session->set('occupation_id' => $occupation_id);
    
    # 省略
    my $drink_id = $c->req->param('drink_id');
    $c->session->set('drink_id' => $drink_id);

};
```

- `occupation_id` や `drink_id` は `my` 付きなので、関数の外には出ないようになっている
- だが、`$c->session->set('occupation_id' => $occupation_id); `というようなコードによってセッションに保存されている状態

https://www.javadrive.jp/perl/var/index3.html

> 変数を宣言するときに my を付けると、その変数はレキシカル変数と呼ばれるものになり、変数を宣言したスコープ内でのみ有効となります。(スコープというのは { から } までのブロック内のことです)。

#### 上記より考えられること
✅ `occupation_id` や `drink_id` を **`confirm` の処理内で再取得する必要がある**
✅つまり、対応する「名前」を取得するためにDBに問い合わせる必要がある➡セッションから occupation_id や drink_id を取得する必要がある？
✅ `name` や `birthdate` は `session` から直接取得できるため、`confirm` 内で改めて取得しなくても動作している

そして`Web\Dispatcher.pm`を次のように修正してみました。


## 正しくはこう？
👇`Web\Dispatcher.pm`
```perl
# 確認ページへの遷移に関わる処理
post '/confirm' => sub {
    my ($c) = @_;
    my $remarks = $c->req->param('remarks') // '';  # undefだった場合、代わりに ''（空文字）を入れる

    $c->session->set('remarks' => $remarks);

    # ここで occupation_id と drink_id を session から取得する
    my $occupation_id = $c->session->get('occupation_id');
    my $drink_id      = $c->session->get('drink_id');

    # データベース接続を作成
    use questionary1::Web::Config;
    my $dbh = DBI->connect(
        "DBI:mysql:dbname=" . questionary1::Web::Config::get('DB_NAME') . ";host=" . questionary1::Web::Config::get('DB_HOST'),
        questionary1::Web::Config::get('DB_USER'),
        questionary1::Web::Config::get('DB_PASS'),
        { mysql_enable_utf8 => 1 }
    );

    # occupation_id に対応する職業名を取得
    my $occupation_name = $dbh->selectrow_array(
        "SELECT name FROM occupation WHERE id = ?", undef, $occupation_id
    );

    # drink_id に対応する飲み物名を取得
    my $drink_name = $dbh->selectrow_array(
        "SELECT name FROM drink WHERE id = ?", undef, $drink_id
    );

    return $c->render('confirm.tx', {
        name       => $c->session->get('name'),
        birthdate     => $c->session->get('birthdate'),
        occupation_name => $occupation_name,
        drink_name      => $drink_name,
        remarks    => $remarks,
    });
};
```

とりあえずこの設定で確認ページにアクセスした際、idではなく名前で表示されるようになりました😊


## さいごに
おそらくもっとスマートな書き方があるのでしょうが、idから名前表示にできただけでも意外と時間がかかってしまったので、今回はここまで。
変数をどこでどのように宣言するかでその後の処理の仕方が変わってくる…学び。💦
この記事が何か参考になれば幸いです。