質問するログイン新規登録

回答編集履歴

2

解説を追加

2021/03/04 04:08

投稿

shinoharat
shinoharat

スコア1685

answer CHANGED
@@ -1,3 +1,5 @@
1
+ ## 修正方法
2
+
1
3
  パスワードの検証が常にONになっているのが原因です。
2
4
  User クラスに以下の修正を加えてください。
3
5
 
@@ -9,4 +11,55 @@
9
11
  + validates :password, format: { 略 }, allow_nil: true
10
12
  ```
11
13
 
12
- 上記の修正により、「パスワードが nil の場合はバリデーションをスキップする」という動作になります。
14
+ 上記の修正により、「パスワードが nil の場合はバリデーションをスキップする」という動作になります。
15
+
16
+
17
+ ## 解説
18
+
19
+ > 疑問なのですがnicknameなどにもpresence: trueをかけているのになぜpasswordのみにバリデーションをスキップするオプションヲッ加えるのでしょうか??
20
+
21
+ 良い質問ですね。password カラムの動作について解説します。
22
+
23
+ 例えば、以下のようなデータを新規作成したとします。
24
+
25
+ ```
26
+ User.create!(nickname: "もっち", email: "aaa@bbb.com", password: "xyz123", ...)
27
+ ```
28
+
29
+ そして、そのデータを find メソッドで取得します。
30
+ すると、nickname や email は保存したときの値が取得できるのですが、 password は nil になっています。
31
+
32
+ ```
33
+ # さっき作成したデータを取得
34
+ user = User.find(さっきのid)
35
+
36
+ # 普通は保存したときの値が取得できる。
37
+ user.nickname #=> "もっち"
38
+ user.email #=> "aaa@bbb.com"
39
+
40
+ # ただし、password は nil になる
41
+ user.password #=> nil
42
+ ```
43
+
44
+ なぜなら、DBに保存されているのは、「password」ではなく「encrypted_password」だからです。
45
+ 確認してみると、encrypted_passwordカラムには、ハッシュ化されたパスワードが格納されているのがわかります。
46
+
47
+ ```
48
+ user.encrypted_password
49
+ => "...ハッシュ化されたパスワード..."
50
+ ```
51
+
52
+ 「password」は「encrypted_password」を作るための一時的な入れ物で、DBと連動しているわけではありません。
53
+ なので、DBからロードしたデータの中には「password」が含まれない(nilになる)という形です。
54
+
55
+ 当然、このまま保存を実行すると、
56
+
57
+ ```
58
+ user.nickname #=> "もっち"
59
+ user.email #=> "aaa@bbb.com"
60
+ user.password #=> nil
61
+ ```
62
+
63
+ の状態でバリデーションされるため、今回のような現象に繋がります。
64
+
65
+ ちなみに、「password」をわざわざ「encrypted_password」に変換して保存するのは、セキュリティ上の理由です。

1

情報が過剰だったので整理

2021/03/04 04:08

投稿

shinoharat
shinoharat

スコア1685

answer CHANGED
@@ -5,13 +5,8 @@
5
5
  **app/models/user.rb**
6
6
 
7
7
  ```diff
8
- # 修正例1:Rails 標準の機能を利用する場合
9
8
  - validates :password, format: { 略 }
10
9
  + validates :password, format: { 略 }, allow_nil: true
11
-
12
- # 修正例2:devise の機能を利用する場合
13
- - validates :password, format: { 略 }
14
- + validates :password, format: { 略 }, if: :password_required?
15
10
  ```
16
11
 
17
12
  上記の修正により、「パスワードが nil の場合はバリデーションをスキップする」という動作になります。