# インターンシップ開発体験:下 v3.5
## 4. データベースの操作
それではデータベースを直接操作してみましょう。
画面と見比べながら結果を確認します。
SQLと呼ばれる言語で操作を行います。
ターミナルは現在、rails sでサーバを動作させていますから、別ウィンドウを開きましょう。ターミナル上部の下矢印からバージョン表記のない無印のUbuntuを選択します。

新しく開いたウィンドウでも、プロジェクトホームに移動し、rubyのバージョンを指定します。
#プロンプトの一部や出力結果は省略しております。
```
$ cd
$ cd project/rails/moneta3.5
$ chruby 3.2.2
```
データベースの操作画面を開くためには以下のコマンドを入力してください。
```
$ rails dbconsole
SQLite version 3.45.1 2024-01-30 16:01:20
Enter ".help" for usage hints.
sqlite>
```
.helpで色々な操作の方法が分かります。.tablesでテーブルの一覧を確認してみましょう。
```
sqlite> .tables
ar_internal_metadata meisais users
kouzas schema_migrations
```
### データの読み取り(select文)
usersテーブルの内容を確認してみましょう。データの読み取りはSQLのselect文を使用します。この時、見やすくするために.modeコマンドも実行しておきましょう。
全ての項目を見るのであれば、*で省略できます。
```
sqlite> .mode line
sqlite> select * from users;
id = 1
bank_bangou = 1000
login_id = test
kanji_name = てすと
kana_name = てすと
hashed_password = 81dc9bdb52d04dc20036dbd8313ed055
email =
yubin =
jusho =
created_at = 2024-08-26 16:11:57.956092
updated_at = 2024-08-26 16:11:57.956092
sqlite>
```
ここでid,kana_nameなどはフィールド名です。フィールド名を指定してテーブル内容を確認することも可能です。上記でアスタリスクだった箇所にカンマ区切りでフィールド名を記載します。
select 項目名 from テーブル名;
```
sqlite> select id, kana_name from users;
id = 1
kana_name = てすと
```
条件を指定してデータを取得するには、where句を使用します。
(また、.modeコマンドで表示形式も変更して、見栄えを調整してみましょう)
```
sqlite> select id,bangou from kouzas where bangou > 5000;
id = 2
bangou = 9294
id = 3
bangou = 8660
sqlite> .mode list
sqlite> select id,bangou from kouzas where bangou > 5000;
2|9294
3|8660
sqlite>
```
kouzasテーブルの内容を確認してみましょう。ユーザーと口座の関係を考えてみると、ユーザーは複数の口座を持ち、口座はひとつのユーザーに所属しています。
```
sqlite> select * from kouzas;
1|1000|101|1|0|1035|1000|2024-08-26 16:12:07.512847|2024-08-26 16:12:29.224386
2|1000|102|1|0|9294|0|2024-08-26 21:03:52.813903|2024-08-26 21:03:52.813903
3|1000|103|1|0|8660|0|2024-08-26 21:03:59.598688|2024-08-26 21:03:59.598688
4|1000|101|1|0|4733|0|2024-08-26 21:04:05.232324|2024-08-26 21:04:05.232324
sqlite> .mode line
sqlite> select * from kouzas;
id = 1
bank_bangou = 1000
shiten_bangou = 101
user_id = 1
kinyu_shohin = 0
bangou = 1035
zandaka = 1000
created_at = 2024-08-26 16:12:07.512847
updated_at = 2024-08-26 16:12:29.224386
id = 2
bank_bangou = 1000
shiten_bangou = 102
user_id = 1
kinyu_shohin = 0
bangou = 9294
zandaka = 0
created_at = 2024-08-26 21:03:52.813903
updated_at = 2024-08-26 21:03:52.813903
id = 3
bank_bangou = 1000
shiten_bangou = 103
user_id = 1
kinyu_shohin = 0
bangou = 8660
zandaka = 0
created_at = 2024-08-26 21:03:59.598688
updated_at = 2024-08-26 21:03:59.598688
id = 4
bank_bangou = 1000
shiten_bangou = 101
user_id = 1
kinyu_shohin = 0
bangou = 4733
zandaka = 0
created_at = 2024-08-26 21:04:05.232324
updated_at = 2024-08-26 21:04:05.232324
sqlite>
```
ある口座自身が所属するユーザーの情報は、漢字の名前ではなく、user_idというフィールドに番号で持っているようです。
meisaisテーブルも確認してみましょう。
```
sqlite> select * from meisais;
id = 1
kouza_id = 1
kubun = 0
kingaku = 0
zandaka = 0
tekiyou = 新規開設
created_at = 2024-08-26 16:12:07.574874
updated_at = 2024-08-26 16:12:07.574874
id = 2
kouza_id = 1
kubun = 1
kingaku = 1000
zandaka = -2000
tekiyou = てすとへの振込
created_at = 2024-08-26 16:12:29.154843
updated_at = 2024-08-26 16:12:29.154843
id = 3
kouza_id = 1
kubun = 1
kingaku = 50
zandaka = -1050
tekiyou = 貸越利息
created_at = 2024-08-26 16:12:29.178559
updated_at = 2024-08-26 16:12:29.178559
id = 4
kouza_id = 1
kubun = 0
kingaku = 1000
zandaka = 1000
tekiyou = てすとからの振込
created_at = 2024-08-26 16:12:29.246813
updated_at = 2024-08-26 16:12:29.246813
id = 5
kouza_id = 2
kubun = 0
kingaku = 0
zandaka = 0
tekiyou = 新規開設
created_at = 2024-08-26 21:03:52.836708
updated_at = 2024-08-26 21:03:52.836708
id = 6
kouza_id = 3
kubun = 0
kingaku = 0
zandaka = 0
tekiyou = 新規開設
created_at = 2024-08-26 21:03:59.619995
updated_at = 2024-08-26 21:03:59.619995
id = 7
kouza_id = 4
kubun = 0
kingaku = 0
zandaka = 0
tekiyou = 新規開設
created_at = 2024-08-26 21:04:05.256455
updated_at = 2024-08-26 21:04:05.256455
sqlite>
```
こちらも同じくとある明細自身が所属する口座の情報は、口座番号などではなく、kouza_idというフィールドに番号で持っているようです。
それでは、口座番号とユーザーかな名を同時に取得するにはどうすれば良いのでしょうか。SQLのjoin構文を使用すると、複数のテーブルの内容を組み合わせて情報を取得できます。
```
sqlite> select users.kana_name, kouzas.bangou from users join kouzas on users.id = kouzas.user_id;
kana_name = てすと
bangou = 1035
kana_name = てすと
bangou = 9294
kana_name = てすと
bangou = 8660
kana_name = てすと
bangou = 4733
sqlite>
```
### データベースコンソールの終了
データベースをSQLで参照する手順は確認できたので、データベースコンソールを終了します。
```
sqlite> .quit
```
### ER図
ユーザーテーブルと口座テーブルの関係のように、データベースではそれぞれのつながりを設定して操作することができました。テーブルによるデータの実体(Entity)と関係(Relation)を図示する方法として、ER図というものが用いられます。
monetaのER図は下記の通りです。
先ほどのselect文では確認しなかったフィールド名を確認することができます。

それぞれのテーブルの日本語の意味は以下の通りです。
モデル名はプログラムから呼び出すときの名前、テーブル名はSQLから呼び出すときの名前です。テーブル名はモデル名の小文字で複数形になっています。
| モデル名 | テーブル名 | 説明
|:-------- |:--------| --------|
|Kouza | kouzas | 口座
|Meisai | meisais | 取引明細
|User | users | ご利用者
### データベースモデルの操作
SQLは強力ですが、少々記述が難しいところがあります。実際の開発では、プログラム言語から扱いやすいようなモデルとして設定しています。javaやrubyなどのオブジェクト指向言語では、ORM(object relation mapper)やDAO(data access object)などと呼びます。
厳密な定義はともかく、やってみましょう。
以下のコマンドでコンソールを開きます。
```
$ rails c
```
cはコンソールの省略形です
ユーザーテーブルはusersでしたね。プログラムではUserオブジェクトとして定義されています。すべての行データを取得するには、allメソッドを使用します。

自動的にSQLが発行された上に、フィールド名まで表示されています。便利ですね。
口座テーブルと明細テーブルを結合して検索してみましょう。

自動生成されたSQLが青字で表示されます。SQLを直接記述する場合に比べて簡潔に記述できていることが分かります。
### 件数の確認
テーブルの件数を確認してみましょう。
スタティックメソッドのcountを使うと、先ほどSQLで記述したcount(*)形式が生成されます。
```
irb(main):006> Kouza.count
Kouza Count (2.0ms) SELECT COUNT(*) FROM "kouzas"
=> 4
irb(main):007>
```
現在の口座テーブルの件数は4件のようです。
### 新規レコードの追加
新しいレコードを追加してみましょう。
レコード追加の前後でcountメソッドも行ってみましょう。
```
irb(main):038> Meisai.count
Meisai Count (0.7ms) SELECT COUNT(*) FROM "meisais"
=> 9
irb(main):039> Meisai.create(id:22,kouza_id:1 )
TRANSACTION (0.1ms) begin transaction
Kouza Load (0.6ms) SELECT "kouzas".* FROM "kouzas" WHERE "kouzas"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
Meisai Create (3.0ms) INSERT INTO "meisais" ("id", "kouza_id", "kubun", "kingaku", "zandaka", "tekiyou", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?) [["id", 22], ["kouza_id", 1], ["kubun", 0], ["kingaku", nil], ["zandaka", nil], ["tekiyou", nil], ["created_at", "2024-08-27 12:08:20.078033"], ["updated_at", "2024-08-27 12:08:20.078033"]]
TRANSACTION (4.1ms) commit transaction
=>
#<Meisai:0x00007f4e4d085c80
id: 22,
kouza_id: 1,
kubun: "nyuukin",
kingaku: nil,
zandaka: nil,
tekiyou: nil,
created_at: Tue, 27 Aug 2024 12:08:20.078033000 UTC +00:00,
updated_at: Tue, 27 Aug 2024 12:08:20.078033000 UTC +00:00>
irb(main):040> Meisai.count
Meisai Count (0.6ms) SELECT COUNT(*) FROM "meisais"
=> 10
irb(main):041>
```
データが追加されました。件数が増えたことが確認できますね。
### レコードの更新
データの更新を行ってみましょう。
インスタンスとしてレコードを取得して、インスタメンスメソッドのupdateを使用します。
```
$ meisai = Meisai.find_by(id:"22")
$ meisai.update(zandaka: "9999999")
$ Meisai.find_by(id:"22")
```
条件を付けての検索(where句)や、update文による更新を行うSQLが生成されていることが分かります。
### レコードの削除
せっかく更新したレコードですが、削除することにします。destroyメソッドを使用します。
$ meisai.destroy
$ Meisai.find(22)
destroyメソッドは条件に合致したレコードをすべて削除します。
findメソッドは、特にID番号で検索するメソッドですが、削除しているので、RecordNotFound(レコードが見つかりません)が出ています。
以上で、データベースについて、参照、追加、更新、削除をやってみることができるようになりました。
### データベースと画面の連携
データベースの情報を好きにできるようになりましたので、
次はそれがどうにかして画面の動きに連動してほしいと思います。
ブラウザでトップページを表示しましょう。
「てすと様」と表示されていますね。
これはusersテーブルに入っています。修正してみましょう。
```
$ user = User.find_by(kanji_name: "てすと")
$ user.update(kanji_name: "更新てすと")
```
「更新てすと」のところは自由に変えてください。

ブラウザをリロードして確認します。

更新されました。
このように、開発・テスト中は、データベースを直接操作しながら確認を行うことがあります。
## 5.プログラムの修正
以上で、データベースの内容変更による画面の変更を確認しました。
次はソースコードを修正します。画面と見比べながら確認していきましょう。
WEBアプリケーションでは、複数のプログラムやデザインの言語を使用します。一度にすべて覚えるのは無理ですから、実現したい内容に応じて少しづつ理解していきましょう。
### エディタの起動
それではいよいよプログラムの修正と確認を行ってみましょう。今回はVisual Studio Codeと呼ばれるエディタを利用します。
以下のようにターミナルに入力して起動します。
先ずはrailss cからexitしていますね。
```
irb(main):051> exit
moneta@localpc:~/project/rails/moneta3.5$ code -a .
```
### プロジェクトエクスプローラ
左列の重なった書類のアイコンをクリックすると、プロジェクトエクスプローラーが開き、ファイルとフォルダの全体が表示されます。たくさんのフォルダがありますね。

まずはview(ビュー)から見ていきましょう。画面定義を行うプログラムが格納されています。
/app/views/users/top.html.erbをクリックします。
```htmlembedded
<div class="container mx-auto w-96 mt-8 px-8 py-4 bg-gray-100">
<div class="text-4xl text-center my-2">ログイン</div>
<form action="/login" method="post">
<label for="login_id" class="mt-4">ユーザーID</label>
<input type="text" name="login_id" id="login_id" value="<%= @login_id %>" class="p-1 border-gray-300 w-full">
<label for="password" class="mt-4">パスワード</label>
<input type="password" name="password" id="password" value="<%= @password %>" class="p-1 border-gray-300 w-full">
<div class="grid grid-cols-2 gap-4">
<input
type="submit"
value="ログイン"
class="cursor-pointer p-2 my-8 text-center rounded bg-blue-500 hover:bg-blue-300 text-white"
/>
<a
href="/users/new"
class="cursor-pointer p-2 my-8 text-center rounded bg-green-500 hover:bg-green-300 text-white"
>
新規ユーザー
</a>
</div>
</form>
</div>
```
ページを定義しているプログラムが表示されました。erbという、HTMLなどの文章の中にRubyスクリプトを埋め込むためのライブラリが使用されています。
ブラウザから画面と見比べてみましょう。ブラウザでF12キーを押すか、右上のメニューボタンから「デベロッパーツール」を開きます。
表示場所は「×」の左の点が三つ縦に並んだボタンから「固定サイド」で変更可能です。
見やすい場所を探してそれぞれ試してみましょう。

デベロッパーツールには開発用の色々な機能がありますが、画面部品の検査機能を使用してみます。
四角を矢印がさしているアイコンをクリックします。

画面内で動かすと、名称の吹き出しや、レイアウトエリアの色分けが表示されます。

色々動かして、ビュープログラムとの関連を確認してみましょう。
### ビューの修正
まずは色を変えてみましょう。top.html.erbの一行目の最後の数字を100から800に変えてctrl+sで保存しましょう。

ブラウザの更新ボタンを押すと暗い感じに変わりました。

色などのデザインにはtailwind cssというを利用しています。そのほかの色やほかのデザイン要素については、リンク先も参照してください。
https://tailwindcss.com/docs/background-color
### ログの確認
サーバ処理のターミナルを見てみましょう。今の処理のログが出力されています。

ログの内容を追うと以下の順番で処理されていることが分かります。
|実施者 | 操作 | 内容|
|:-------- |:-------|:--------|
|ブラウザ | 送信 | GET /top|
|コントローラ | UsersController | topメソッドを実施|
|ビュー | users/top.html.erb | 画面表示用htmlを生成|
|ブラウザ | 受信・描画 | 受け取ったhtmlで画面を描画|
### コントローラの修正
それでは次は、コントローラ(UsersController)を修正してみましょう。プロジェクトエクスプローラからapp/controller/を探して開きます。

ファイルの数が多いので、探すことも大変です。エディタが横断検索の機能を提供しているので以下のように行うこともできます。
ctrl+pを押して表示された窓に、ファイル名の一部を入力してみましょう。必ずしも連続していなくてもかまいません。下の例ではuseconと入力しています。

いくつか候補が表示されるので、上下矢印+enterかクリックして開きましょう。
### コントローラーとメソッド
topメソッドの内容を見るとずいぶんすっきりしています。
```
# GET /top
def top
@login_id = session[:login_id]
@password = session[:password]
# /app/views/users/top.html.erb
render :top
end
```
先頭に'@'が付いている変数はインスタンス変数と言い、コントローラーからビューへのデータの受け渡しに使用されます。
セッションから取得した情報を、インスタンス変数に格納してビューに送っていることがわかりました。
```
# POST /login
def login
login_id = params[:login_id]
password = params[:password]
user = User.find_by(login_id: login_id)
```
topの次のloginメソッドを見てみると、User.find_byの書き方は、データベースの確認の時に見ましたね。
ターミナルのrails cで確認可能なので、気になる処理は実際に動かしてみましょう。
### リンクボタンの追加
振込先銀行選択画面ですが、振込元口座選択画面に戻るボタンがなくて不便ですね。

画面の下の方に「戻る」ボタンを追加してみましょう。
戻りたい画面のurlは localhost:3000/furikomi/select_moto_kouza のようです。ターミナルで表示されているログから確認できますが、これがGET "/furikomi/select_moto_kouza" に変換されて送信されているんでしたね。
app/views/furikomi/select_bank.html.erb の最終行に以下の通り追加して確認してみましょう。
```htmlembedded
<div class="flex flex-row-reverse mt-2">
<a href="/furikomi/select_moto_kouza" class="px-4 py-1 bg-blue-500 hover:bg-blue-300 text-white rounded">戻る</a>
</div>
```
戻るボタンが追加されました。クリックして一つ前の画面に戻ることを確認してみましょう。

## 6.内部設計
それでは、発見したバグの発生場所と原因の調査を進めていきましょう。
グループワークになりますので、だれがどのバグの調査をするのか、話し合って手分けして行います。
障害箇所と原因が分かれば、修正方針を記載できるはずです。それを設計としておきましょう。
### バグの探し方
バグの場所の探し方は色々ありますが、実際に操作を行いログを追ってみることで、処理が行われたプログラムと行番号を知ることもできます。
口座開設を行ってログを見ると、先ずは支店選択画面をGETしているようです。

次に、「開設する」ボタンをクリックすると、POST "/futsu_yokin"から処理が始まり、app/controllers/futsu_yokin_controller.rb 13の'create'メソッドでSQLのINSERT文が発行されているようです。

そのプログラムの13行目を見てみると、確かにsaveメソッドです。なにやら保存処理をしているようですね。
```=13
kouza = Kouza.create!(
bank_bangou: "1000",
shiten_bangou: shiten_bangou,
user_id: @user.id,
kinyu_shohin: :futsu_yokin,
zandaka: 0,
bangou: random_kouza_bangou(),
)
```
ログをさらに追うと、INSERT文が続いています。
app/controllers/futsu_yokin_controller.rb:22 in 'create'
プログラムの該当処理を見てみると、明細作成処理のようです。
### ルーティング
URLから、コントローラーやメソッドへの紐づけをルーティングと呼び、ルーティングを行う機能をルーターと呼びます。
ルーターの定義は、config/routes.rbで行っています。

例えばGET /loginが、UsersControllerのloginメソッドに送られていることが分かります。
### 設計レビュー
グループ内で、まずはバグの修正担当を割り振りましょう。できれば設計者とは別のメンバーが修正したほうが良いでしょう。
実際の業務でも、設計者と開発者のコミュニケーションは重要な要素であるため、その練習です。
自分の設計内容の説明をしましょう。どのようなバグで、どのようにモジュールを特定したか説明しましょう。
特に修正担当のメンバーは「この報告内容で正しく自分が修正に取り掛かれるか」を考えながら、不足があれば指摘します。指摘内容は反映しましょう。
## 7.開発(コーディング)
自分の担当分の修正開発を行っていきます。プログラムを修正して動作を確認します。
その前に、色々修正した状態を確認しましょう。
```
$ git diff
```
ファイル毎の修正内容が確認できます。ページの色の変更は戻しましたか。振込の途中の戻るボタンはそのままにしておきましょう。
```
$ git add --all
$ git status
```
修正したプログラムが緑で表示され、登録候補(ステージング)になったことが示されます。
何かファイルを適当に修正しましょう。壊してしまってもかまいません。(2-3行削除するとか)
git add時点に戻すには、以下のコマンドを使用します。
```
$ git checkout .
```
元に戻ったでしょうか。
### gitによるソードコード管理
gitでは、修正したファイルは以下のような順番で管理されます。
|順番 | コマンド | 名称 | 説明 |
|:-------- |:--------:|:--------:|:--------|
| 1 | 未登録 | 登録前 |(statusで赤字) |
| 2 | add | ステージング | ファイル単位で仮登録 |
| 3 | commit | コミット | まとめて登録する |
| 4 | push | プッシュ | githubに登録する |
一つのバグについて修正を行い、動作確認が済んだら、ステージングに続いて、コミットを行います。
```
$ git add --all
$ git commit -m "Fix バグの説明"
```
今回の開発体験では、githubの原本の修正までは行いません。
### visual studio codeによる差分表示
左列のツールアイコンから、二股に枝分かれしたアイコンをクリックします。小さな丸付き数字は、修正してコミットしていないファイルの数です。
コードの差分が色付きで表示されますので、レビューに適しています。
ファイルを選択すると、左右に修正前後の内容が並んで表示されます。赤色が削除部分、黄色が追加部分です。
指摘や質問があれば、メモを取りましょう。
### コードレビュー
プログラムの修正が終わったら、講師かチューターを交えてコードレビューを行います。
## 8. 振り返り
本日の成果を報告しましょう。不備・障害一覧には、担当者名で絞り込みを行う機能があります。その機能を使って、自分が担当した「報告」「設計」「開発」「検証」について振り返りを行うと良いでしょう。
慌ただしくも駆け足の対応でしたが、お疲れ様でした。
:::success
:bulb: **5daysの内容はそれぞれ関わりがあります**
## 応用的なコンテンツ 次期システムや機能追加の要件定義
さて、バグの修正を中心に開発の流れを追ってきましたが、お客様からシステム化の要望を受けて開発を行う場合、実現したい機能を元に要件定義を行います。
時間があればグループワークとして、monetaの新機能を考えて、システム化の検討を行っていきましょう。今現在、お客様からは次のような要望が出ています。
- 振込手数料について、銀行別の別段預金口座に収容して、残高、明細を確認できるようにしたい。
- お客様情報を一覧できるマイページを追加し、ログイン直後に表示させたい。
- 外貨預金について複数通貨の取扱を可能にしたい。
- 手数料をもっと細かく設定したい。銀行が異なる場合、支店が異なる場合で別の手数料にしたい。
また、開発部門からの提案として、これ以外のテーマを選定しても構いません。グループで話し合って幾つかテーマを選定したら、報告にまとめましょう。
### リファクタリング
我々が開発したシステムは5年〜10年と長いあいだ利用されます。その間プログラムの修正が発生するたびに、ソースコードを見て修正する場所を探したり、影響の有無を確認する作業が発生します。
プログラムの読みやすさを保つための変更は、リファクタリングと呼ばれますが、システムを安定して運用するための大事な取り組みになります。
例えば、app/helpers/application_helper.rb は使われていないように見えます。未使用のコードは混乱の元ですから、削除してしまったほうが良いはずですが、思わぬところで影響が出るかもしれません。
リファクタリングによる修正もバグ報告に登録します。
### 自動テスト
リファクタリングによる無影響を確認する場合に自動テストがあると安心です。
rails testという自動テストを準備しておけば、
未使用コードを削除して、rails testで検証することが可能です。
もし、テストでエラーが発生していたら、git checkout .で戻すことができます。
### 要件定義レビュー
グループワークにより整理した内容について、他のグループに説明しましょう。説明を聞いた他のグループは、不明瞭な部分については質問して明確にしましょう。
指摘事項を反映して修正したら、要件定義書、設計書を設定します。
:::