はじめに
Rails チュートリアルなどで、Railsの勉強をしていて、$ Rails c
を利用してDB(今回はMySQL
)のレコードの操作に関して調べていたら勉強になったので、まとめておきます。
環境
この記事では以下の環境(2018年6月25日時点)で動作確認できました。
- Ruby: 2.4.1
- Rails: 5.0.7
モデル設計
今回はWebアプリケーションでよく見るユーザーのモデルを作成していきます。
今回は必要なカラムは、
- ユーザの名前
- ユーザのメールアドレス
- ログイン認証のためのユーザパスワード(
bcrypt
というGem
で暗号化される)
上のカラムを作成するモデルを生成します。
$ rails g model User name:string email:string password_digest:string
生成されたモデルファイルにバリデーションを加えました。
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
データベース
上記のモデルファイルからマイグレーションを実行したら、以下のような仕様のテーブルが確認できます。
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コンソールでレコードの操作
[ミス] パスワードが暗号化されずに入ってしまった
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を確認してみましょう。
+----+----------+--------------------+--------------------------------------------------------------+---------------------+---------------------+
| 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
)
user6 = User.new(name: 'pass6666', email: 'pass6666@gmail.com', password_digest: '6666')
password
という名前のカラム名に入ったデータを bcrypt
(Gem
) が暗号化して、暗号化された後のデータがpassword_digest
というカラムに格納されます。なので、はじめから password_digest
と指定してしまうと、暗号化されずに格納されてしまいます。
ただしくは、以下のようにするべきでした。
user6 = User.new(name: 'pass6666', email: 'pass6666@gmail.com', password: '6666')
インスタンスの更新
update
メソッドを使って、インスタンスのデータを更新できます。
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
のレコードのパスワードが暗号化されて格納されました。
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 |
+----+----------+--------------------+--------------------------------------------------------------+---------------------+---------------------+
以上です!
この記事を読んだ方に
この記事を読んで、誤っている箇所をみつけたり、追記した方がいい内容などありましたら、編集リクエストやコメント欄で指摘していただけると助かります。