chatGPTに頼りまくって作成したrails初心者向け勉強会資料

# 本ページのゴール
* ruby on railsの特性についてなんとなく理解する
* ruby on railsを構成する各要素の役割とそれぞれの繋がりについて理解する
* chatGPTを利用して、より効率的に資料作成できるようになる

# 概要
色々あり、webアプリケーション開発をほぼしたことが無いsreチームメンバ向けに、勉強会を開くことになりました。

しかし勉強中の身で体系的にrailsについてまとめるのは辛い...
そこでchatGPTをフル活用して資料作成してやろうという考えに

railsを構成する各要素についてまとめつつ、随所にchatGPTとのやり取りを乗せていきます

# 目次
[1 RubyとRailsの紹介](https://qiita.com/takeba/items/fa7e47cac530c740aa32#1-ruby%E3%81%A8rails%E3%81%AE%E7%B4%B9%E4%BB%8B)
[2 開発環境のセットアップ](https://qiita.com/takeba/items/fa7e47cac530c740aa32#2-%E9%96%8B%E7%99%BA%E7%92%B0%E5%A2%83%E3%81%AE%E3%82%BB%E3%83%83%E3%83%88%E3%82%A2%E3%83%83%E3%83%97)
[3 railsの基本](https://qiita.com/takeba/items/fa7e47cac530c740aa32#3-rails%E3%81%AE%E5%9F%BA%E6%9C%AC)
[4 データベースとの連携](https://qiita.com/takeba/items/fa7e47cac530c740aa32#4-%E3%83%87%E3%83%BC%E3%82%BF%E3%83%99%E3%83%BC%E3%82%B9%E3%81%A8%E3%81%AE%E9%80%A3%E6%90%BA)
[5 テスト](https://qiita.com/takeba/items/fa7e47cac530c740aa32#5-%E3%83%86%E3%82%B9%E3%83%88)

<details>
  <summary>いくつか質問を投げ、その中から必要そうなトピックだけ選びました</summary>

![スクリーンショット 2023-03-28 17.30.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/948431/849e7af9-c83d-3ec7-0854-8e73fafa1ab6.png)
![スクリーンショット 2023-03-28 17.29.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/948431/7bd61df1-c924-7fc1-56dd-9fef86d204f5.png)
</details>

# 1 RubyとRailsの紹介
rubyとrailsとはそもそも何なのか紹介しています。
<details>
  <summary>chatGPTとのやりとり</summary>

![スクリーンショット 2023-03-28 14.54.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/948431/6404a04e-2cb7-c1e6-7077-5dac0a258219.png)
</details>

## 1.1 Rubyとは何か

Rubyは、まつもとゆきひろ（Matz）氏によって開発されたオブジェクト指向のスクリプト言語です。簡潔で読みやすく、生産性の高いコードを書くことができます。RubyはWebアプリケーション開発や自然言語処理、テスト自動化など、様々な用途に利用されています。

## 1.2 Ruby on Railsとは何か

Railsは、David Heinemeier Hansson氏によって開発されたRuby用のWebアプリケーションフレームワークです。Railsは、Model-View-Controller（MVC）アーキテクチャを採用しており、開発者が高速にWebアプリケーションを構築することができます。

## 1.3 Ruby on Railsの特徴や用途

Railsは、以下のような特徴や用途があります。

- 高速なWebアプリケーション開発が可能
- MVCアーキテクチャを採用しており、アプリケーションの設計が容易
- ActiveRecordというORMを採用しており、データベースとのやりとりが簡単
- シンプルで美しいコードを書くことができ、生産性が高い
- 多くの拡張機能（Gem）が提供されており、柔軟な開発が可能
- スケーラビリティが高く、大規模なアプリケーションの構築にも適している

Ruby on Railsは、Webアプリケーション開発をはじめるための優れたフレームワークです。

<details>
  <summary>特徴を聞いたらベタ褒めだったのであえて悪い点を聞いてみた</summary>

![スクリーンショット 2023-03-28 14.52.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/948431/64a81720-bc74-7ea9-c318-e95d1c4e1967.png)
</details>


# 2 開発環境のセットアップ
　本筋ではないのですごくざっくり書いています。実際にセットアップする際は他の有能な記事を参考にして下さいmm

<details>
  <summary>chatGPTとのやりとり</summary>

![スクリーンショット 2023-03-28 14.55.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/948431/b77238c5-27e9-bd43-d486-2b7d44cceacd.png)
</details>

## 2.1 Rubyのインストール

まず、Rubyをインストールする必要があります。Rubyは、公式サイトからダウンロードすることができます。以下の手順に従ってインストールしてください。

1. 公式サイト（https://www.ruby-lang.org/ja/downloads ）にアクセスし、最新バージョンのRubyをダウンロードします。
2. ダウンロードしたファイルをダブルクリックし、インストーラを起動します。
3. インストーラの指示に従って、インストールを完了します。

## 2.2 Railsのインストール

次に、Railsをインストールする必要があります。RubyGemsを使ってインストールすることができます。以下の手順に従ってインストールしてください。

1. コマンドプロンプトを開きます。
2. `gem install rails`というコマンドを入力します。
3. インストールが完了したら、`rails -v`というコマンドを入力して、バージョンが表示されることを確認します。

## 2.3 テキストエディタの選択と設定

最後に、開発に使用するテキストエディタを選択し、設定する必要があります。おすすめのテキストエディタとしては、Atom、VS Code、Sublime Textなどがあります。選択したテキストエディタに合わせて、必要に応じて設定を行ってください。

Ruby on Railsの開発に必要な環境は以上の3つです。しっかりとセットアップしましょう。

***
自分がセットアップ時に参考にした記事: [【完全版】MacでRails環境構築する手順の全て](https://qiita.com/kodai_0122/items/56168eaec28eb7b1b93b)

# 3 railsの基本
 railsを構成する各要素について説明しています。
<details>
  <summary>chatGPTとのやりとり</summary>

(一部だけ抜粋)
![スクリーンショット 2023-03-28 14.58.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/948431/c393bccc-4889-46e9-69a1-a74d4ad03e27.png)

流石にこれだけのオープンクエスチョンで帰ってくる回答だけでは内容が薄くなりそうだったので、随所に情報を足しています。
</details>

## 3.1 フレームワークとは
　アプリケーション開発におけるフレームワークとは、一般的に再利用可能な標準的な構造と基盤を提供する開発用のソフトウェアです。<br>　フレームワークは、特定のプラットフォーム、プログラミング言語、またはアプリケーションの種類に合わせて設計されています。フレームワークには、データベース接続やテンプレートエンジン、セキュリティ機能、ルーティング機能、コントローラやモデルなどの標準的なコンポーネントが含まれることが多いため、開発者はこれらの機能を自分で実装する必要がなくなり、開発効率の向上が期待できます。<br>　また、フレームワークにはコミュニティが存在しており、情報交換や質問に対する回答、さらには機能拡張のためのプラグインやGemが公開されていることがあります。

<details>
  <summary>世界的に広く利用されているフレームワーク5選</summary>

* Ruby on Rails（ルビーオンレイルズ）
  * Ruby言語で書かれたWebアプリケーションフレームワーク
  * 簡単なコードでWebアプリケーションを開発できることが特徴
* Django（ジャンゴ）
  * Python言語で書かれたWebアプリケーションフレームワーク
  * 強力なORM（Object-Relational Mapping）により、簡単なコードでデータベースとのやり取りができることが特徴
* Express.js（エクスプレス）
  * Node.jsで動作するWebアプリケーションフレームワーク
  * 軽量で高速なことが特徴
* Laravel（ララベル）
  * PHP言語で書かれたWebアプリケーションフレームワーク
  * MVCアーキテクチャを採用し、簡単なコードでWebアプリケーションを開発できることが特徴
* Spring Framework（スプリングフレームワーク）
  * Java言語で書かれたWebアプリケーションフレームワーク
  * 豊富な機能を持ち、大規模なWebアプリケーションの開発に向いていることが特徴
<details>
  <summary>chatGPTとのやりとり</summary>

![スクリーンショット 2023-03-28 15.07.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/948431/29f8f038-c33c-70c0-bb8c-60acc4e3cd37.png)
</details>
</details>

## 3.2 プロジェクトの作成
Ruby on Railsで開発を始めるには、最初にプロジェクトを作成する必要があります。プロジェクトを作成するには、ターミナルで以下のコマンドを入力します。
```
$ rails new [プロジェクト名]
```
このコマンドを実行すると、プロジェクトのディレクトリが作成され、基本的なファイルやディレクトリが自動的に生成されます。

<details>
  <summary>作成されるディレクトリ(ファイルの一覧)</summary>

* **app**: アプリケーションの主要な機能を含むディレクトリです。コントローラ、モデル、ビュー、ヘルパーなどが含まれます。
* bin: アプリケーションの実行可能ファイルが含まれるディレクトリです。rails、rake、bundleなどのコマンドが含まれます。
* **config**: アプリケーションの設定ファイルが含まれるディレクトリです。database.yml、**routes.rb**、application.rbなどが含まれます。
* **db**: データベースのマイグレーションファイルが含まれるディレクトリです。schema.rbファイルも含まれます。
* lib: アプリケーション固有の拡張機能や共有機能を含むディレクトリです。
* log: アプリケーションのログファイルが含まれるディレクトリです。
* public: 静的ファイルが含まれるディレクトリです。画像、CSS、JavaScriptなどが含まれます。
* **test**: テストコードが含まれるディレクトリです。test.rbやfixturesなどが含まれます。
* tmp: 一時ファイルが含まれるディレクトリです。cacheやpidsなどが含まれます。
* vendor: アプリケーションに必要な外部ライブラリが含まれるディレクトリです。
* **Gemfile**: Railsアプリケーションに必要なRubyのライブラリ（gem）を定義するファイルです。このファイルには、アプリケーションに必要なgemの名前とバージョンがリストされています。`bundle install`コマンドを実行することで、Gemfileに基づいて各種モジュールをインストールできます。

<details>
  <summary>chatGPTとのやりとり</summary>

![スクリーンショット 2023-03-28 15.10.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/948431/932c26aa-0086-f046-f977-ea48024148d2.png)
</details>
</details>

## 3.3 MVCアーキテクチャ
Ruby on Railsは、MVCアーキテクチャに基づいて設計されています。MVCとは、Model-View-Controllerの略で、アプリケーションを3つの役割に分ける設計手法です。

* **Model**: データの管理、操作を行う
* **View**: ユーザーインターフェースを担当する
* **Controller**: ユーザーの入力を受け取り、ModelとViewを連携させる
MVCアーキテクチャは、アプリケーションを複数の役割に分割することで、コードの保守性や可読性を向上させることができます。

<details>
  <summary>MVCアーキテクチャ</summary>

![mvc_detailed.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/948431/01351b9c-06f4-47be-b912-0e52992b3e0b.png)

https://railstutorial.jp/chapters/toy_app?version=5.1#sec-mvc_in_action より参照
</details>

<details>
  <summary>コード例</summary>

(config/routes.rb)
```Ruby
Rails.application.routes.draw do
    get '/index', to: 'users#index'
end
```

(app/controllers/users_controller.rb)
```Ruby
class UsersController < ApplicationController
  def index
    @users = User.all
  end
end
```

(app/models/user.rb)
```Ruby
# app/models/user.rb

class User < ApplicationRecord
  validates :name, presence: true
end

```

(app/views/users/index.html.erb)
```Ruby
<h1>Users</h1>
<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Email</th>
    </tr>
  </thead>
  <tbody>
    <% @users.each do |user| %>
      <tr>
        <td><%= user.name %></td>
        <td><%= user.email %></td>
      </tr>
    <% end %>
  </tbody>
</table>
```

<details>
  <summary>chatGPTとのやりとり</summary>

![スクリーンショット 2023-03-29 13.47.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/948431/a12d27a7-0b16-dc7b-3bc9-3c7f73329dce.png)
</details>
</details>

## 3.4 ルーティング
Ruby on Railsでは、URLをコントローラーとアクションにマッピングする仕組みがあります。これをルーティングと呼びます。

ルーティングは、config/routes.rbファイルに定義されています。以下は、例として「/hello」のURLにアクセスされたときに、welcomeコントローラーのhelloアクションを呼び出すルーティングの定義です。
```Ruby
get '/hello', to: 'welcome#hello'
```
このように定義することで、ブラウザから「/hello」にアクセスすることで、welcomeコントローラーのhelloアクションが呼び出されます。

## 3.5 コントローラ
コントローラは、ユーザーからのリクエストを受け取り、処理を行い、ビューを呼び出す役割を担います。Ruby on Railsでは、コントローラを生成するには以下のコマンドを使用します。
```
$ rails generate controller [コントローラ名]
```

<details>
  <summary>上記コマンドで作成されるファイル一覧</summary>

* **app/controllers/[コントローラ名]_controller.rb**: 指定されたコントローラ名に対応するコントローラファイルです。
* **app/views/[コントローラ名]**: 指定されたコントローラ名に対応するビューファイルが格納されるディレクトリです。
* **test/controllers/[コントローラ名]_controller_test.rb**: 指定されたコントローラ名に対応するテストファイルです。
* app/assets/stylesheets/[コントローラ名].scss: 指定されたコントローラ名に対応するSCSSファイルです。
* app/assets/javascripts/[コントローラ名].coffee: 指定されたコントローラ名に対応するCoffeeScriptファイルです。

<details>
  <summary>chatGPTとのやりとり</summary>

![スクリーンショット 2023-03-28 15.22.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/948431/b6d56c0d-0e00-1923-9b21-e488a5aa0c51.png)
</details>
</details>

例えば、下記コードではUserモデルの全量を@users変数に格納し、ビューに渡しています。
ビューとの連携部分が明記されておらず自分は初め混乱したのですが、ビューファイルの呼び出しについて
* コントローラのアクション名に対応するビューファイルを呼び出すことができる。
    * (app/views/controller_name/action_name.html.erb　が呼び出される)
* コントローラのアクションで render メソッドを呼び出すことで、明示的にビューファイルを指定することができる。

つまり、UsersControllerのindexアクションが呼び出されると、自動的にapp/views/users/index.html.erb というビューファイルが返される。

(app/controllers/users_controller.rb)
```Ruby
class UsersController < ApplicationController
  def index
    @users = User.all
  end
end
```

## 3.6 モデル
モデルは、データの管理や操作を行う役割を担います。Ruby on Railsでは、モデルを生成するには以下のコマンドを使用します。
```
$ rails generate model [モデル名]
```
<details>
  <summary>上記コマンドで作成されるファイル一覧</summary>

* **db/migrate/YYYYMMDDHHMMSS_create_[モデル名].rb**: データベースマイグレーションファイルです。テーブルを作成するためのスキーマを定義します。
* **app/models/[モデル名].rb**: モデルファイルです。ActiveRecordを用いて、テーブルと対応するモデルクラスを定義します。
* **test/models/[モデル名]_test.rb**: モデルのテストファイルです。Minitestを用いて、モデルの各種メソッドが期待通りに動作することを確認します。

<details>
  <summary>chatGPTとのやりとり</summary>

![スクリーンショット 2023-03-28 15.25.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/948431/2503de46-f225-34c4-5c6e-3af24de8f728.png)
</details>
</details>

モデルはdbと密接に関わる部分なので、詳しくは4章に記載しています。

## 3.7 ビュー
ビューは、コントローラが処理した結果を表示するための役割を担います。Ruby on Railsでは、ビューを生成するには以下のコマンドを使用します。
```
$ rails generate view [コントローラ名] [アクション名]
```

<details>
  <summary>上記コマンドで作成されるファイル一覧</summary>

* **app/views/[コントローラ名]/[アクション名].html.erb**: HTMLテンプレートファイルです。ビューを表現します。
* app/views/[コントローラ名]/[アクション名].html.slim: Slimテンプレートファイルです。HTMLの記述を簡素化することができます。
* **test/controllers/[コントローラ名]_controller_test.rb**: コントローラのテストファイルです。Minitestを用いて、アクションの動作を確認します。

<details>
  <summary>chatGPTとのやりとり</summary>

![スクリーンショット 2023-03-28 15.27.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/948431/3109bc99-772a-442a-a572-e764c4f71e63.png)
</details>
</details>

### 3.7.1テンプレートエンジン
Ruby on Railsでは、ビューのテンプレートエンジンとしてERB（Embedded Ruby）が標準で使用されています。ERBは、HTML内にRubyのコードを埋め込むことができるテンプレートエンジンであり、ビューの作成に広く使用されています。

ERBを使用する場合、HTMLファイルの拡張子を「.html.erb」とする必要があります。例えば、welcomeコントローラーのhelloアクションのビューを作成する場合は、「hello.html.erb」というファイル名で作成する必要があります。

<details>
  <summary>erbファイルの記述例</summary>

```Ruby
<% @users.each do |user| %>
  <li><%= user.name %></li>
<% end %>
```

この例では、@usersというインスタンス変数に格納されたユーザー情報を、eachメソッドを使って1つずつ取り出しています。そして、ユーザーの名前をuser.nameで取得し、<li>タグで囲っています。<%= %>で囲まれたコードブロックは、その中で評価された値がHTMLに埋め込まれます。

</details>

# 4 データベースとの連携
<details>
  <summary>chatGPTとのやりとり</summary>

(内容が簡素すぎる&実例がないと説明しづらい内容だったので、半分以上自力で追記)
![スクリーンショット 2023-03-28 16.08.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/948431/c0c78222-1a11-3b6a-f957-3b05048290a5.png)
</details>

## 4.1 ActiveRecord
ActiveRecordは、Ruby on RailsのMVCのMの部分であるモデル層を担当するフレームワークであり、データベースとのやりとりを簡単に行うことができます。

ActiveRecordは、データベースのテーブルとモデルクラスを1対1に対応させることができます。クラスベースのデータベーススキーマ定義をサポートしており、マイグレーション機能を使ってスキーマの変更を追跡・管理することができます。また、Active Recordには、データベーステーブルを操作するための様々なメソッドが用意されています。例えば、createメソッドを使って、新しいレコードを作成することができます。

<details>
  <summary>マイグレーション機能一覧</summary>

* **create_table**：新しいテーブルを作成します。
* **add_column**：既存のテーブルに新しいカラムを追加します。
* **remove_column**：既存のテーブルからカラムを削除します。
* **change_column**：既存のカラムのデータ型やオプションを変更します。
* rename_column：既存のカラムの名前を変更します。
* **add_index**：既存のテーブルにインデックスを追加します。これにより、データベースの検索速度が向上します。
* remove_index：既存のテーブルからインデックスを削除します。
* add_reference：既存のテーブルに外部キーを追加します。
* remove_reference：既存のテーブルから外部キーを削除します。
* create_join_table：2つのテーブルを結合するための中間テーブルを作成します。
* drop_join_table：中間テーブルを削除します。
</details>

## 4.2 マイグレーション
マイグレーションは、データベースの構造を変更するための仕組みです。Railsでは、マイグレーションを使ってデータベースのスキーマを管理します。

マイグレーションは、データベースの変更を行うためのRubyスクリプトであり、db/migrateディレクトリに保存されます。マイグレーションを実行することで、データベースの構造が自動的に変更されます。

### マイグレーションの具体的な流れ
例えば、usersテーブルを作成するためのマイグレーションを作成する場合は、以下のようになります。

```
$ rails generate migration create_users
```

このコマンドを実行すると、db/migrateディレクトリにYYYYMMDDHHMMSS_create_users.rbという形式のマイグレーションファイルが生成されます。<br>
作成されたマイグレーションファイルに必要なカラム情報を追記することもできます。
```Ruby
class CreateUsers < ActiveRecord::Migration[6.1]
  def change
    create_table :users do |t|
      t.string :name
      t.integer :age

      # usersテーブルに追加したいカラムをここに記述する
      t.string :email
      t.string :password_digest

      t.timestamps
    end
  end
end
```
(id, created_at, updated_atというカラムは明示的に定義しなくても自動的に追加される。)

マイグレーションファイルを定義後、`rails db:migrate`コマンドを実行することで、内容がdbに反映されます。<br>
また`rails db:migrate`を実行すると、マイグレーションファイルに記述された変更内容を基に`db/schema.rb`というファイルが自動的に更新されます。つまり、最新のdbの状態は`db/schema.rb`ファイルを参照すれば確認することができます。
```Ruby
ActiveRecord::Schema.define(version: 2023_03_23_090539) do

  create_table "users", force: :cascade do |t|
    t.string "name"
    t.string "email"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.string "password_digest"
    t.index ["email"], name: "index_users_on_email", unique: true
  end

end
```

### 4.3 DBとモデルの紐付け
#### 4.3.1 ApplicationRecordについて
ApplicationRecord は Rails 5 以降で導入されたクラスで、Railsのモデルクラスの親クラスとなっています。ApplicationRecord クラスには下記のような機能が実装されています。

* データベースのテーブルとの紐付け
* バリデーション
* コールバック

`データベースのテーブルとの紐付け`について詳しく見ていきます。
この機能により、命名規則に従って自動的にテーブルとモデルの紐付けが行われます。具体的には、Userモデルはusersテーブルに、Postモデルはpostsテーブルに紐づけられます。


つまり4.2で出てきたusersテーブルに登録されるuser情報について、下記のようにモデルを定義することができます。
<details>
  <summary>4.2のusersテーブル情報</summary>

```Ruby
ActiveRecord::Schema.define(version: 2023_03_23_090539) do

  create_table "users", force: :cascade do |t|
    t.string "name"
    t.string "email"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.string "password_digest"
    t.index ["email"], name: "index_users_on_email", unique: true
  end

end
```
</details>

userモデルクラス
```Ruby
class User < ApplicationRecord
    # 受け取ったメールアドレスを全て小文字に変換する
    before_save { self.email = email.downcase }
    # ユーザ名について文字数制限を設ける
    validates(:name, presence: true, length: {maximum: 50})
    # メールアドレスについてバリデーションチェックを行う
    VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
    validates(:email, presence: true, 
        length: {maximum: 255}, 
        format: { with: VALID_EMAIL_REGEX }, 
        uniqueness: { case_sensitive: false })

```
(自分はApplicationRecordについての説明を読み飛ばして実装を進めたせいで、どこでDBの情報をとってきているのか理解できずかなり時間を無駄にした。)

#### 4.3.2 実際にUserモデルを介してUsersテーブルにデータを反映してみる
```
$ rails console
``` 
で、アプリケーションの環境に入り対話形式でRubyコードを実行することができます

<details>
  <summary>(再掲)Usersテーブル</summary>

```Ruby
ActiveRecord::Schema.define(version: 2023_03_23_090539) do

  create_table "users", force: :cascade do |t|
    t.string "name"
    t.string "email"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.string "password_digest"
    t.index ["email"], name: "index_users_on_email", unique: true
  end

end
```
</details>

<details>
  <summary>(再掲)Userモデル</summary>

```Ruby
class User < ApplicationRecord
    before_save { self.email = email.downcase }
    validates(:name, presence: true, length: {maximum: 50})
    VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
    validates(:email, presence: true, 
        length: {maximum: 255}, 
        format: { with: VALID_EMAIL_REGEX }, 
        uniqueness: { case_sensitive: false })
    has_secure_password
    validates :password, presence: true, length: { minimum: 6 }
end
```
</details>

* User情報を登録できるか
```C
2.7.0 :012 > hoge_user = User.create(name: 'hoge', email: 'hogea@gmail.com', password: 'hogehoge', password_confirmation: 'hogehoge')
   (0.0ms)  begin transaction
  User Exists (0.1ms)  SELECT  1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER(?) LIMIT ?  [["email", "hogea@gmail.com"], ["LIMIT", 1]]
  User Create (0.4ms)  INSERT INTO "users" ("name", "email", "created_at", "updated_at", "password_digest") VALUES (?, ?, ?, ?, ?)  [["name", "hoge"], ["email", "hogea@gmail.com"], ["created_at", "2023-03-28 07:37:15.290544"], ["updated_at", "2023-03-28 07:37:15.290544"], ["password_digest", "$2a$10$.iHyjQQHUi/zN/29sydUqumXXZf3fulzQyIGi0Zy8FJJW1ZCF.nEe"]]
   (5.8ms)  commit transaction
```
作成できました。
本筋とは関係ないですが、なぜ**password**が**password_digest**としてハッシュ化されて登録されているかは[railsチュートリアル](https://railstutorial.jp/chapters/modeling_users?version=5.1#sec-adding_a_secure_password)を参照してください。
(シンプルな例を作るべきところですが、サボって既存の環境を使い回しました。ごめんなさい。)
* インデックスの制約(メールアドレスの一意制約)に反するモデルを作成しようとした場合

```C
2.7.0 :011 > hoge_user = User.create(name: 'hoge', email: 'hoge@gmail.com', password: 'hogehoge', password_confirmation: 'hogehoge')
   (0.0ms)  begin transaction
  User Exists (0.3ms)  SELECT  1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER(?) LIMIT ?  [["email", "hoge@gmail.com"], ["LIMIT", 1]]
   (0.1ms)  rollback transaction
```
登録できず、rollbackされました。
* モデルで定義したバリデーションチェックに反するモデル(passwordが6文字未満)を登録しようとした場合
```C
2.7.0 :014 > aaaaa_user = User.create(name: 'aaaaaaa', email: 'aaaaa@gmail.com', password: 'aaaa', password_confirmation: 'aaaa')
   (1.3ms)  begin transaction
  User Exists (0.3ms)  SELECT  1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER(?) LIMIT ?  [["email", "aaaaa@gmail.com"], ["LIMIT", 1]]
   (0.1ms)  rollback transaction
```
こちらも登録できず。

<details>
  <summary>rollback時のエラーメッセージについて</summary>

一意制約に反して`User Exists`が返されるのは分かるが、バリデーションチェックで弾かれる際にも`User Exists`になるのは納得いきません。
chatGPTに聞いてみたら、Active Recordがエラーを内部でキャッチして実情と異なるメッセージを返してしまうことは有名な話らしいです。特にuniquenessバリデーションについては頻繁に返されるため、信頼性が薄いらしいです。

<details>
  <summary>chatGPTとのやりとり</summary>

![スクリーンショット 2023-03-28 17.23.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/948431/4aec2c92-f417-47dc-d6a7-4c76b696dd8e.png)
![スクリーンショット 2023-03-28 17.24.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/948431/5fc90b9b-b78f-fd01-ad25-44cd5a4f2425.png)

</details>

</details>


#### 4.3.3 モデル同士の関連付け
(app/models配下のお話)
Railsでは、異なるテーブル同士を関連付けることができます。例えば、ユーザーが複数の投稿を持つ場合、has_manyとbelongs_toを使って、UserモデルとPostモデルを関連付けることができます。

```Ruby
class User < ApplicationRecord
  has_many :posts
end

class Post < ApplicationRecord
  belongs_to :user
end
```

このようにすることで、user.postsのようにして、ユーザーが持つ投稿を全て取得することができます。逆に、post.userのようにして、投稿が属するユーザーを取得することもできます。

# 5 テスト
## 5.1 テストフレームワーク
railsにはデフォルトでMinitestとRSpecの2つのテストフレームワークが用意されています。基本的にどちらか一方を採用することが多いらしいです。

### 5.1.1 Minitest
Railsには軽量で標準的なテストフレームワークであるMinitestが含まれています。MinitestはRuby標準のテストフレームワークであるTest::Unitの代替として作られました。以下はMinitestの主な機能や使い方の解説です。

Minitestでは、テストは通常、testディレクトリ内のファイルに書かれます。各ファイルはクラスとして定義され、テストケースはそのクラスのインスタンスメソッドとして書かれます。例えば、Userモデルのnameのバリデーションチェックに関するテストを行う場合、下記のようになります。
<details>
  <summary>テスト例</summary>

```Ruby
# test/models/user_test.rb
require 'test_helper'

class UserTest < ActiveSupport::TestCase
  test "name should be present" do
    user = User.new(name: "", email: "test@example.com", password: "password")
    assert_not user.valid?
  end
end
```
</details>

テストは`rails test`で実行することができます。

Minitestでは、アサーションを使ってテストの結果をチェックします。アサーションは、以下のようなものがあります。
<details>
  <summary>アサーションの一覧</summary>

* ssert: 引数がtrueであることを確認する
* refute: 引数がfalseであることを確認する
* assert_equal: 2つの引数が等しいことを確認する
* assert_not_equal: 2つの引数が等しくないことを確認する
* assert_nil: 引数がnilであることを確認する
* assert_not_nil: 引数がnilでないことを確認する
</details>

### 5.1.2 RSpec
　RSpecは、Rubyプログラミング言語のBDD（行動駆動開発）フレームワークで、Railsのテストフレームワークの一つです。RSpecを使用することで、アプリケーションの動作を詳細に定義し、それをテストすることができます。RSpecは、Railsアプリケーションのコントローラ、モデル、ビュー、ルーティング、ヘルパーメソッドなど、さまざまな側面をテストするための柔軟な機能を提供しています。

　Minitestに比べて柔軟性が高く、読みやすさに優れています。また、RSpecは、モックやスタブなどの機能を提供しており、Railsアプリケーションの開発をより容易にするための豊富な機能を提供しています。

こちらもMinitestと同様にユーザモデルのnameのバリデーションチェックに関するテストを記述すると下記のようになります。
<details>
  <summary>テスト例</summary>

```Ruby
# spec/models/user_spec.rb
require 'rails_helper'

RSpec.describe User, type: :model do
  it "name should be present" do
    user = User.new(name: "", email: "test@example.com", password: "password")
    expect(user).not_to be_valid
  end
end
```
</details>

ここで、**describe**と**it**はRSpecのメソッドです。

アサーションは、以下のようなものがあります。
<details>
  <summary>アサーションの一覧</summary>

* expect(actual).to eq(expected)：actualとexpectedが等しいことを検証します。
* expect(actual).to be(expected)：actualがexpectedと同じオブジェクトであることを検証します。
* expect(actual).to be_truthy：actualが真であることを検証します。
* expect(actual).to be_falsey：actualが偽であることを検証します。
* expect(actual).to be_nil：actualがnilであることを検証します。
* expect(collection).to include(expected)：collectionにexpectedが含まれていることを検証します。
* expect(actual).to respond_to(expected)：actualがexpectedというメソッドに応答することを検証します。
* expect { block }.to raise_error(expected)：blockの実行中にexpectedというエラーが発生することを検証します。
* expect(actual).to match(/expression/)：actualが/expression/という正規表現にマッチすることを検証します。
</details>

### 5.1.3 MinitestとRSpecの比較
* 構文: RSpecはDSL（Domain Specific Language）でテストを記述することができ、人間が自然な形でテストコードを記述できることが特徴です。一方、MinitestはRubyの標準的なassertion構文を使った書き方をすることができます。
* 使い方: RSpecはテスト駆動開発（TDD）や行動駆動開発（BDD）といったアジャイル開発手法においてよく用いられます。Minitestは、Railsに同梱された標準的なテストフレームワークであり、Railsの機能や挙動を確認するための単体テストを行う場合によく使われます。
* 機能: RSpecには、Minitestにはない多数の機能があります。例えば、RSpecはFactoryBotやCapybaraなどの便利なライブラリを使ってテストを書くことができます。

すごく雑にいうと、Minitestは単体テストに、RSpecは統合テストやシステムテストにおいて優位性があるようです。

## 5.2 テストの種類
　railsにおけるテストは、主に単体テスト(モデルテスト)、機能テスト(コントローラテスト)、統合テスト(システムテスト)の3つがあります。
### 5.2.1 単体テスト(モデルテスト)
　単体テストとは、モデルのバリデーションやメソッドの振る舞いを確認するテストです。例えば、データベースに保存される前にモデルが有効であるかどうかを検証するために、モデルに定義されたバリデーションをテストすることができます。単体テストは、アプリケーションの中で最も単純であるため、最初に実装されることが多く、より細かい単位でテストを実行することができます。

5.1で書いたテストは全て単体テストにあたります。
ですので実装例は省略します。

### 5.2.2 機能テスト(コントローラテスト)
 機能テストとは、コントローラーのアクションやビューの表示など、機能全体のテストです。例えば、ユーザーがログインしたときに、正しいページにリダイレクトされるかどうかを検証することができます。機能テストは、単体テストよりも大きな範囲をカバーすることができますが、アプリケーション全体をテストするわけではないため、統合テストが必要な場合もあります。

3.5に記載している通り、`$ rails generate controller [コントローラ名]` を実行すると自動的にコントローラのテストファイルも生成されます。

**UsersController**の**index**アクションが HTTP 200 ステータスコードを返すかどうかを確認するテストの実装例を記載しておきます。
<details>
  <summary>テスト実装例(RSpec)</summary>

```Ruby
# test/controllers/users_controller_test.rb
require 'test_helper'

class UsersControllerTest < ActionController::TestCase
  test "should get index" do
    get :index
    assert_response :success
  end
end
```
</details>

ActionController::TestCaseクラスはRailsアプリケーションのapp/controllersディレクトリ内に定義されたコントローラークラスを自動的にインポートします。これにより、自動的にUsersControllerがインポートされています。


### 5.2.3 統合テスト(システムテスト)
　統合テストとは、実際のアプリケーションと同じ環境でテストを実行し、全体的な動作を確認するテストです。例えば、ユーザーがログインしてから、新しい記事を投稿し、それを表示するまでの一連の動作を検証することができます。統合テストは、アプリケーション全体をテストするため、より高いレベルのテストとなります。

まず、
```C
rails generate system_test <test_name>
```
を実行し、`test/system/`配下にテストファイルを生成します。そして、そこにシステムテストを実装していきます。

<details>
  <summary>テスト実装例(RSpec)</summary>

```Ruby
require "application_system_test_case"

class UsersTest < ApplicationSystemTestCase
  test "visiting the index" do
    visit users_url

    assert_selector "h1", text: "Users"
  end

  test "creating a User" do
    visit users_url

    click_on "New User"

    fill_in "Name", with: "Test User"
    fill_in "Email", with: "test@example.com"
    fill_in "Password", with: "password"
    fill_in "Password confirmation", with: "password"

    click_on "Create User"

    assert_text "User was successfully created"
    assert_selector "h1", text: "Users"
  end
end
```

* test "visiting the index"では、visitメソッドでusers_urlにアクセスし、assert_selectorメソッドで"Users"というテキストが存在するかどうかを検証しています。

* test "creating a User"では、visitメソッドでusers_urlにアクセスし、"New User"というテキストが表示されているリンクをクリックして、フォームに値を入力して送信するという操作を行い、最後に作成されたユーザーが一覧に表示されていることを検証しています。
</details>

システムテストを実行するためには
```C
rails test:system
```
コマンドを実行します。


# 感想
* 自力で書くよりも圧倒的に短い工数で書き上げることができた
    * ざっくり8時間くらいで書き上げることができた
* 外部サイトを使うことなく、ほぼchatGPTだけで完結したので楽だった
    * 初段の返信だけでは説明が不十分なことがあった
    * だが、何回かラリーすることで十分な内容までもって行けた
* 資料作成と学習を同時にできたのは期待通り
    * ラリーを繰り返すことで分からないことが全て解決するのですごく楽しい
* たまに嘘ついて来るので注意が必要
    * オープンクエスチョンすると、細部で間違っていることがあった
    * 気になったらより前提条件を明示して質問し直すことが必要

# 参考
* https://openai.com/blog/chatgpt
* https://railstutorial.jp/chapters/toy_app?version=5.1