【テーブル？】railsのモデルやデータベースが何をしているのか分からない人へ【migration？】

# 前説
DMM WebCampのAdvent Calendar2021の4日目を担当させていただきました、日置と申します。

Railsのモデルやデータベース関係で何をしているのか分からず困っている方向けに、railsにおけるデータの扱い方について説明していきたいと思います。よろしくお願いします。

### この記事の最終目標
1. テーブルの意味を理解する
1. migrationファイルル/schemaファイルと、rails db:~コマンドの役割を理解する
1. Modelとは何かを理解する
1. Modelの使い方を覚える

### 対象者
- Rubyの以下の基礎知識を把握している方
    - 文字列の結合や数値の計算
    - 変数
    - メソッドと引数([参考](https://www.javadrive.jp/ruby/method/index3.html))
- RailsのModelが何をしているのか分からない方
- rails db:migrateが何をしているのか分からない方

### 目次
- テーブルの意味を理解する
    - [RailsとDB](#railsとdb)
    - [DBのデータの形式](#dbのデータの形式)
- migrationファイル/schemaファイルとrails db:~コマンドの役割を覚える
    - [migrationファイル/schemaファイルとは何か](#migrationファイルとは何か)
    - [テーブルの定義](#テーブルの定義)
    - [マイグレーションとrails db:~コマンド](#マイグレーションとrails-db)
- Modelとは何かを理解する
    - [Railsのデータの形式](#railsのデータの形式)
    - [Modelの正体](#modelの正体)
- Modelの使い方を覚える
    - [DBからデータを取り出す](#dbからデータを取り出す)
    - [取り出したデータを扱う](#取り出したデータを扱う)
    - [データをDBに追加する](#データをdbに追加する)

# テーブルの意味を理解する
### この項目の目標
- DBとは何かを理解する
- テーブル、カラム、レコード、値の意味を理解する

## RailsとDB
テーブルを理解する上でまず念頭において欲しいのは、Railsとデータベース(以下DB)は、全くの別のものという事です。

- 「Rails」とはサイトを表示させたり、データを処理するためのアプリケーション
- 「DB」とは、データを長期的に保存しておくためのアプリケーション

つまり皆様は、「Rails」+「DB」でアプリケーションを作成しているわけですね。

|アプリ|言語|データの形態|できること|
|---|---|---|---|
|Rails|Ruby|インスタンス|ブラウザにHTMLを表示したり、計算処理をする|
|DB|SQL|テーブル|データを保存する|

このように使っている言葉も仕組みも全く違うものなので、DBの話を読むときは、Railsと切り離して考えていただけると理解がしやすいです。

## DBのデータの形式
### データの形式
**データベースのデータは、エクセルの表の様に保存**されています。**この表自体がテーブル**です。
下は、学校の生徒の表の例です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602432/6e785308-9f27-4d84-17bc-58b34ff4ddd3.png)

この表は、テーブル、カラム、レコード、値という4つの要素で出来ています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602432/d0d488b0-6e86-5ae9-096f-ef9f66d4407b.png)
次からこの4つを順に説明していきます。


### テーブル
先ほども書きましたが、テーブルとはこの表自体の事です。1つの事柄(生徒、先生、教室等)につき、1テーブルを作成します。
通常、テーブルは英単語の複数系で定義します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602432/84a99bb9-e41b-c667-50ff-4a04b0ff3b03.png)


### カラム
**カラムとは情報の属性**の事です。学年、名前等、情報が何を指しているのかを示す物。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602432/5009c387-da99-1d94-00af-7050f404d269.png)

### レコード、値
**値とはカラムの中身(1年生、田中太郎等)の事**です。
**レコードとは、1データ分のカラムの値をまとめて一つの情報にしたもの**です。一人の生徒の情報(学年番号1の、学年が1年生の、名前が田中太郎の生徒)、一人の先生の情報、一つの教室の情報等。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602432/92fdb6c7-44ca-c4e2-7a2e-922f3e261d71.png)

## まとめ
下記の事が分かっていれば、今回の項目の理解は完璧です。

- RailsとDBは別のアプリケーション
- テーブルを構成する4つの要素




# migrationファイルとrails db:~コマンドの役割を覚える
## migrationファイルとは何か
**migrationファイルとは、Railsから、DBのテーブルを定義(作成)したり、既存のテーブルの定義を変更したりするためのファイル**です。
後に説明するマイグレーションを行う際、このmigrationファイルの通りにテーブルが定義/変更されます。
**schemaファイルとは、DBの状態を見やすくまとめたファイル**です。

そしてここで重要なのが、**migrationファイルの書き方や、schemaファイルの見方はわざわざ覚える必要はありません！**
読み書きするたびに、分からなくなったら調べれば良いからです。この記事でもmigrationファイルの作成については説明しません。

次は、その代わりに理解していただきたい、テーブルを定義するとは具体的に何をする事なのかについて説明していきます。

## テーブルの定義
テーブルを定義には、2つの事を決めます

- テーブル名
- カラム

テーブル名はそのまんま、何についての情報なのかを英単語複数系で決めればokです。
カラムの定義では以下の事を決めます

- カラムの名前
- カラムのデータ型
- カラムの制約

##### カラムの名前
スネークケース(大文字を使わない記述方式)で記述しましょう。他にも暗黙の了解のような命名規則があります。

##### カラムのデータ型
文字や数値等、値の種類の事です。一つのカラムには同じデータ型の値しか入りません。

##### カラムの制約
NULL(空の状態)禁止、デフォルトでは1等のルールです。細かい説明はここでは省略します。初歩の段階では特に気にしなくても問題ありません。

migrationファイルでは、これらを設定しています。

## マイグレーションとrails db:~
ターミナルで実行するこのrails db:~系のコマンドは、railsからDBのテーブルの作成や変更(マイグレーション)を行ったり、DB自体をリセットするために行うものです。

このコマンドを理解するには、先にマイグレーションについて知る必要があります(単語は難しそうですが、少しの説明で終わります！)。

### マイグレーション
migrationファイルは、作成しただけではDBに影響を与えません。
マイグレーション(rails db:migrate)という事を行う事で、migraionファイルの内容がDBに反映されます。
**なおテーブル作成時は、migrationファイルに書かれていないidというカラムが自動で追加されます**

この時、マイグレーションを行って**DBに反映されている状態のmigrationファイルをup状態**、**まだ反映されていない状態のmigrationファイルをdown状態**と言います。

up状態のmigrationファイルは、もう一度マイグレーションを行っても無視されるため、注意が必要です。(**つまり、up状態のmigrationファイルを書き換えても意味がないです！**)

### コマンド
rails db:~というコマンドは、基本的に以下の3つを覚えておけば大丈夫です！

- rails db:migrate
- rails db:migrate:status
- rails db:migrate:reset

##### rails db:migrate
マイグレーションを行います。

##### rails db:migrate:status
今あるマイグレーションファイルのup, downを確認できます。

##### rails db:migrate:reset
データベースを初期化(DB内のデータを削除、migrationファイルを全てdownに)して、新たにマイグレーションを行います。
migrationファイルがごちゃごちゃしてしまった時、必要なもの以外を消してこちらを実行することで、必要なmigrationファイルだけがある状態からやり直せます。

## まとめ
下記の事が分かっていれば、今回の項目の理解は完璧です。

- migrationファイルとは、テーブルを定義/変更するためのもの
- テーブルを定義するとは、テーブル名とカラムの内容を決める事
- マイグレーションを行うと、migrationファイルの内容がDBに反映される


# Modelとは何かを理解する
## Railsのデータの形式
テーブルを理解するためにDBのデータの形式を覚えたように、Modelを理解するためにはRails(Ruby)のデータの形式を理解する必要があります。
なので、ここからはRubyの話になってきます。
Rubyでは、データをクラスというもので管理しています。

### クラスの定義
クラスとは、Rubyのテーブルのようなもので、指定したデータ(生徒、先生など何についてのデータか)の型を定義したものです。

`※この記事では、簡単に説明してしまいますが、いずれ必要な知識なので、気になる方は以下の記事を参考にしてみてください。(その際はこのRailsのデータ形式の項目は読み飛ばしていただいて大丈夫です)`
[オブジェクトとは](https://qiita.com/digitter/items/6c232f0b07a0d78cd74f)

クラスを作成する時に定義するものの内、今回は以下の3つについて触れていきます。

- クラス名
- インスタンス変数
- メソッド

コードの例を載せていますが、**コードを覚えたり理解する必要はない**ので安心してください。

##### クラス名
1文字目を大文字にした、英単語単数で定義します。(例: Student)

```Ruby
class Student
end
```

##### インスタンス変数
テーブルのカラムのようなものです。
テーブルのカラムと違うところは、データ型を決める必要がなく、自由に値を入力できます。

```Ruby
class Student
  # gradeとnameを定義
  def initialize(grade: nil, name: nil)
    # この@~がカラムのようなもの
    @grade = grade
    @name = name
  end
end
```

Railsを勉強していると、controllerからviewにデータを渡すための変数として、インスタンス変数が出てくると思うのですが、あれとは用途が違うので、今回は別物だと考えてください。

##### メソッド
これはテーブルにはないものです。
クラスには、そのクラスに保存する値の種類(インスタンス変数)の他に、そのクラスに関する機能(メソッド)を定義できます。
メソッドには2種類あります。

- インスタンスメソッド(後述するインスタンスを対象とした機能)
- クラスメソッド(クラス自体の機能)

```Ruby
class Student
  def initialize(grade: nil, name: nil)
    @grade = grade
    @name = name
  end

  # 名前の後に学年を付けた文字列を返すメソッドを定義(インスタンスメソッド)
  def out_put_data
    "#{@name} #{@grade}年"
  end
end
```

### インスタンス
インスタンスとは、定義したクラスに所属しているオブジェクト(データ)の事です。
**DBのレコードと似ています**。
クラス名.new(値)で生成でき、下記のように表示されます。

`#<Student:~ @grade=1, @name="田中太郎">`

```Ruby
class Student
  # gradeとnameを定義
  def initialize(grade: nil, name: nil)
    @grade = grade
    @name = name
  end
end

student = Student.new(grade: 1, name: "田中太郎")
# studentという変数に、Studentクラスのインスタンスが入る
```

### メソッドの使い方
それぞれ以下の方法で呼び出す

- インスタンスメソッド: インスタンス.メソッド
- クラスメソッド: クラス名.メソッド

メソッドには2種類あって、それぞれ役割と呼び出し方違うという事が分かればok

```Ruby
class Student
  def initialize(grade: nil, name: nil)
    @grade = grade
    @name = name
  end

  def out_put_data
    "#{@name} #{@grade}年"
  end
end

student = Student.new(grade: 1, name: "田中太郎")

# インスタンスメソッドを使う
puts student.out_put_data #=> 田中太郎 1年
```

## Modelの正体
Railsでは、migrationファイルでDBにテーブルを作成できました。
**Modelとは、この作成したテーブルに対応したRails(Ruby)のクラス**の事です。
**1つのテーブルに付き、担当のModelが1つ**あります。

Modelには、Railsで使っている言葉(Ruby)と、DBで使っている言葉を翻訳して、DBにデータを追加できるメソッドがたくさん用意されています。

## まとめ
以下の事を理解していれば問題ありません。

- Rubyでは、クラスと言うものを定義し、データをそのインスタンスとして扱う
- クラスには、インスタンス変数とメソッドを定義できる
- クラスのメソッドには2種類ある
- Modelとは、DBのテーブルに対応したRubyのクラス


# Modelの使い方を覚える
いよいよ最後の項目、Modelの扱い方についての説明です。

## DBからデータを取り出す
DBからデータを取り出して、Railsのインスタンスに変換するには、4種類のModelのクラスメソッドから適切なものを使います。
データを取り出してくる際、**DBのレコードをRubyのクラスのインスタンスとして変換**してくれます。

|メソッド名|データの取り出し方|
|---|---|
|.all|テーブルのすべてのレコードを取得|
|.where|条件を指定して、それにあうレコードを取得|
|.find|数値や文字を指定して、それと同じidカラムの値を持つレコードを取得|
|.find_by|条件を指定して、それにあうレコードから最初の1つを取得|

これらはクラスメソッドなのでModel名.メソッド名の形で記述します。

```Ruby:books_controller.rb
# BookというModelがある状態

def index
  @books = Book.all # booksテーブルのレコード全てをBookクラスのデータに変換
end

def show
  @book = Book.find(1) # booksテーブルのidカラムの値が1のレコードを、Bookクラスのデータに変換
end
```



`期日に間に合わなかったので、以下後日追記致します。。。`
## 取り出したデータを扱う
取り出したデータから、インスタンスメソッドを呼び出す(取り出したデータ.メソッド名)で、データの読み書きや削除が行えます

|メソッド名|処理|
|---|---|
|.カラム名|カラムの値を取得|
|.update(編集したいカラム: 値)|DBのレコードを書き換える|
|.destroy|DBからレコードを削除する|

```Ruby:books_controller.rb
def test
  # booksテーブルのidカラムの値が1のレコードをBookクラスのインスタンスに変換
  book = Book.find(1)

  # ※booksテーブルにtitleというカラムがある前提
  # booksテーブルのid1のレコードのtitleカラムの値を表示
  puts book.title

  # booksテーブルのid1のレコードのtitleカラムの値を'テストデータ'に変更
  book.update(title: 'テストデータ')

  # booksテーブルのid1のレコードを削除
  book.destroy
end
```

## データをDBに追加する
DBにレコードを追加するには、先にModelのインスタンスを作成して、そこからsaveメソッドを呼び出します。

```Ruby:books_controller.rb
  def create
    # newメソッドで、インスタンス変数@titleの値が'テストデータ'のインスタンスを作成
    book = Book.new(title: 'テストデータ')

    # booksテーブルにtitleカラムの値が'テストデータ', idカラムの値が今のレコード数+1、のレコードを追加
    book.save
  end
```

## まとめ
以下の事を理解していれば問題ありません。

- Modelのメソッドは、DBとRailsのデータを相互に変換してくれる
- カラム名メソッドを使うと、そのカラムの値が取得できる
- update, destroyメソッドで、編集、削除が行える
- newとsaveを組み合わせることで、DBにレコードを追加できる

# 最後に
以上でRailsのデータベース関連の説明は終わりです。
少しでも読んでくださった方のRailsを触る上での不明点が少なくなったり、ストレスが減ったりしたら嬉しいです。