Rails コンソールで mysql のレコードを操作する方法

# はじめに

[Rails チュートリアル](https://railstutorial.jp/)などで、Railsの勉強をしていて、`$ Rails c` を利用してDB（今回は`MySQL`）のレコードの操作に関して調べていたら勉強になったので、まとめておきます。

# 環境

この記事では以下の環境（2018年6月25日時点）で動作確認できました。

- Ruby: 2.4.1
- Rails: 5.0.7

# モデル設計

今回はWebアプリケーションでよく見るユーザーのモデルを作成していきます。

今回は必要なカラムは、

- ユーザの名前
- ユーザのメールアドレス
- ログイン認証のためのユーザパスワード（ `bcrypt` という`Gem` で暗号化される）


上のカラムを作成するモデルを生成します。

```bash
$ rails g model User name:string email:string password_digest:string
```

生成されたモデルファイルにバリデーションを加えました。

```app/models/user.rb
class User < ApplicationRecord

  # バリデーション
  # 保存前に全てを小文字変換
  before_save { self.email.downcase! }
  validates :name, presence: true, length: { maximum: 50 }
  validates :email, presence: true, length: { maximum: 255 },
                    format: { with: /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i },
                    uniqueness: { case_sensitive: false }
  # 「password」と「password_confirmation」という項目をフォームで送るとbcryptが勝手に暗号化し
  # 「password_digest」というカラムに暗号化したデータを入れる
  # https://qiita.com/chobi9999/items/20b962a324a0bdbfc0dc
  has_secure_password

end

```

# データベース

上記のモデルファイルからマイグレーションを実行したら、以下のような仕様のテーブルが確認できます。

```sql
mysql> describe users;
+-----------------+--------------+------+-----+---------+----------------+
| Field           | Type         | Null | Key | Default | Extra          |
+-----------------+--------------+------+-----+---------+----------------+
| id              | int(11)      | NO   | PRI | NULL    | auto_increment |
| name            | varchar(255) | YES  |     | NULL    |                |
| email           | varchar(255) | YES  |     | NULL    |                |
| password_digest | varchar(255) | YES  |     | NULL    |                |
| created_at      | datetime     | NO   |     | NULL    |                |
| updated_at      | datetime     | NO   |     | NULL    |                |
+-----------------+--------------+------+-----+---------+----------------+
```

# Railsコンソールでレコードの操作

## [ミス] パスワードが暗号化されずに入ってしまった

```console
user6 = User.new(name: 'pass6666', email: 'pass6666@gmail.com', password_digest: '6666')

 => #<User id: nil, name: "pass6666", email: "pass6666@gmail.com", password_digest: "6666", created_at: nil, updated_at: nil> 

2.4.1 :025 > user6.save
   (0.3ms)  BEGIN
  User Exists (0.3ms)  SELECT  1 AS one FROM `users` WHERE `users`.`email` = 'pass6666@gmail.com' LIMIT 1
  SQL (0.1ms)  INSERT INTO `users` (`name`, `email`, `password_digest`, `created_at`, `updated_at`) VALUES ('pass6666', 'pass6666@gmail.com', '6666', '2018-06-24 16:57:30', '2018-06-24 16:57:30')
   (1.7ms)  COMMIT
 => true 
```

DBを確認してみましょう。

```sql
+----+----------+--------------------+--------------------------------------------------------------+---------------------+---------------------+
| id | name     | email              | password_digest                                              | created_at          | updated_at          |
+----+----------+--------------------+--------------------------------------------------------------+---------------------+---------------------+
|  1 | pass1111 | pass1111@gmail.com | $2a$10$6Q6zqlKSmzZ9Heh2PF9SkuTVSBDO0wQgKJb5Huul1RlDdZG5uOJ3i | 2018-06-23 10:33:55 | 2018-06-24 16:06:28 |
|  2 | pass2222 | pass2222@gmail.com | $2a$10$2twR9S6gduK5ZNnHhdFTueNGtgmA1LrDQwdM0uX857ATMyfwM4W0e | 2018-06-23 10:35:37 | 2018-06-24 16:34:22 |
|  3 | pass3333 | pass3333@gmail.com | $2a$10$Vj6XZ4mExZxKWby4zqN0Pe7p5L3B2USSKcPYFFTvsZyFLA9BAJxtG | 2018-06-23 10:38:20 | 2018-06-24 16:55:21 |
|  4 | pass4444 | pass4444@gmail.com | $2a$10$rMOPVU8hqMXGaVyOR/f77O1H.PoMpkvZMWasVub6EoPpSd1wD4g1i | 2018-06-24 16:02:08 | 2018-06-24 16:55:35 |
|  5 | pass5555 | pass5555@gmail.com | $2a$10$ROHi3Bjf1qAnZ0zMy0IZT.d/QFg6UYh20hZbBGCqKafbk7jZ8v35a | 2018-06-24 16:05:10 | 2018-06-24 16:05:10 |
|  6 | pass6666 | pass6666@gmail.com | 6666                                                         | 2018-06-24 16:57:30 | 2018-06-24 16:57:30 |
+----+----------+--------------------+--------------------------------------------------------------+---------------------+---------------------+
```

最後のレコードのパスワードが、暗号化されなかった原因は、
`User`インスタンスを生成する際、カラム名（`password_digest`）を間違えてたことです。
（ただしくは、`password`）

```console
user6 = User.new(name: 'pass6666', email: 'pass6666@gmail.com', password_digest: '6666')
```

`password`という名前のカラム名に入ったデータを `bcrypt`（`Gem`） が暗号化して、暗号化された後のデータが`password_digest` というカラムに格納されます。なので、はじめから `password_digest` と指定してしまうと、暗号化されずに格納されてしまいます。

ただしくは、以下のようにするべきでした。

```console
user6 = User.new(name: 'pass6666', email: 'pass6666@gmail.com', password: '6666')
```

## インスタンスの更新

`update` メソッドを使って、インスタンスのデータを更新できます。

```console
2.4.1 :026 > User.find(6).update_attributes(password: "6666")

User Load (0.6ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 6 LIMIT 1
   (0.3ms)  BEGIN
  User Exists (0.3ms)  SELECT  1 AS one FROM `users` WHERE `users`.`email` = 'pass6666@gmail.com' AND (`users`.`id` != 6) LIMIT 1
  SQL (0.2ms)  UPDATE `users` SET `password_digest` = '$2a$10$fCsGUjGPbSDd7klrSe1hiOdJFURLpS57gsJTPrLfF5p48a/a62RBO', `updated_at` = '2018-06-24 17:07:12' WHERE `users`.`id` = 6
   (2.0ms)  COMMIT
 => true 
```

# 結果

IDが`6`のレコードのパスワードが暗号化されて格納されました。

```sql
mysql> select * from users;

+----+----------+--------------------+--------------------------------------------------------------+---------------------+---------------------+
|  1 | pass1111 | pass1111@gmail.com | $2a$10$6Q6zqlKSmzZ9Heh2PF9SkuTVSBDO0wQgKJb5Huul1RlDdZG5uOJ3i | 2018-06-23 10:33:55 | 2018-06-24 16:06:28 |
|  2 | pass2222 | pass2222@gmail.com | $2a$10$2twR9S6gduK5ZNnHhdFTueNGtgmA1LrDQwdM0uX857ATMyfwM4W0e | 2018-06-23 10:35:37 | 2018-06-24 16:34:22 |
|  3 | pass3333 | pass3333@gmail.com | $2a$10$Vj6XZ4mExZxKWby4zqN0Pe7p5L3B2USSKcPYFFTvsZyFLA9BAJxtG | 2018-06-23 10:38:20 | 2018-06-24 16:55:21 |
|  4 | pass4444 | pass4444@gmail.com | $2a$10$rMOPVU8hqMXGaVyOR/f77O1H.PoMpkvZMWasVub6EoPpSd1wD4g1i | 2018-06-24 16:02:08 | 2018-06-24 16:55:35 |
|  5 | pass5555 | pass5555@gmail.com | $2a$10$ROHi3Bjf1qAnZ0zMy0IZT.d/QFg6UYh20hZbBGCqKafbk7jZ8v35a | 2018-06-24 16:05:10 | 2018-06-24 16:05:10 |
|  6 | pass6666 | pass6666@gmail.com | $2a$10$fCsGUjGPbSDd7klrSe1hiOdJFURLpS57gsJTPrLfF5p48a/a62RBO | 2018-06-24 16:57:30 | 2018-06-24 17:07:12 |
+----+----------+--------------------+--------------------------------------------------------------+---------------------+---------------------+
```

---

以上です！

# この記事を読んだ方に

この記事を読んで、誤っている箇所をみつけたり、追記した方がいい内容などありましたら、編集リクエストやコメント欄で指摘していただけると助かります。

# 参考
- https://qiita.com/kinokosan/items/47bb53d01f3dfe61852d