Railsチュートリアル(第6版)の10.1.4 -TDDで編集を成功させる でつまり、
午前中いっぱいかけて解消させた疑問の備忘録です。
私以外の人はこんなところでつまらないかもしれないですが・・
##つまったところと疑問点
####つまったところ:パスワードが空のままでも更新できるようにする
「ユーザー情報を編集する際、いちいちパスワードを入力するのは不便なので
パスワードを変えないときは、入力しなくてもユーザー情報を更新できるようにする。」
という内容。
具体的には、現状
class User < ApplicationRecord
has_secure_password
validates :password, presence: true, length: { minimum: 6 }
となっていて、nilや空文字、6文字未満のパスワードは受け入れられないところを
class User < ApplicationRecord
has_secure_password
validates :password, presence: true, length: { minimum: 6 }, allow_nil: true
と、allow_nil
というオプションで、パスワードが空だった時の例外処理を与える(バリデーションをスキップする)よ。
ということでした。
何が疑問なの?という方、どうかこの記事をそっと温かくスキップしてください
####疑問点:そもそも、presence: true書く必要あったの??
なぜにそんな疑問が生まれてしまったのかというと、チュートリアル中の、
「allow_nilによって新規登録時にパスワードがなくても登録できちゃう!?と心配になるけど、
has_secure_password
がオブジェクト生成時に存在性を検証するようになっているから、
その心配もいらないよ!」
という文。
(簡略化してます。語弊があったら申し訳ないです。。)
以下、私の疑問と疑問が生まれる原因となった勘違いです。
- 新規登録時はパスワード必須にしたい →
has_secure_password
で検証できる - 編集時はパスワード入れなくても更新できるようにしたい →
has_secure_password
はオブジェクト生成時にのみ、存在性を検証するので、編集時はパスワード入れなくてもOK!
⇒ あれ、has_secure_password
だけで完結する?presence: true
いらなくない・・?
大事なことを見落としていたわけですね。
##結論:編集時、空の場合はスキップしたいが、空文字の場合はバリデーションかけねば。
改めて、下記3点を明確にしておきたいと思います。
-
has_secure_password
:DBにレコードが生成された時だけ存在性のvalidationをおこなう -
presence: true
: 値がnil
や空文字
でないことを確認 -
allow_nil
: 対象の値がnil
の場合にvalidationをスキップ = 値が空文字
の場合はvalidationにひっかかる
つまり、presence: true
は書いておかないと、
「編集時、パスワード欄にスペースを打ちこまれちゃった場合にも更新ができてしまう」
のでしたね・・
##どうやって疑問を解消したのか
「presence: true
いらなくない・・?」と思っていたので
presence: true
を消して、下記の状態でテストを回してみました。
class User < ApplicationRecord
has_secure_password
validates :password, length: { minimum: 6 }, allow_nil:true
すると下記統合テストはGREENに。
test "successful edit" do
get edit_user_path(@user)
assert_template 'users/edit'
name = "Foo Bar"
email = "foo@bar.com"
patch user_path(@user), params: { user: {name: name,
email: email,
password: "",
password_confirmation: "" }}
assert_not flash.empty?
assert_redirected_to @user
@user.reload
assert_equal name, @user.name
assert_equal email, @user.email
end
やはりpresence: true
いらないのか・・?と思ったそのとき、
別のテストが私に思い出させてくれました。
test "password should be present (nonblank)" do
@user.password = @user.password_confirmation = " " * 6
assert_not @user.valid?
end
こちらがしっかりREDになっていた!
まずこのテストはユーザを新規登録せずにパスワードの値を空文字に設定しているため
has_secure_password
の検証にはひっかかりません。
そしてpresence: true
を消してしまったがために、空文字入力がOKになり、
ユーザーが有効になってしまったのでテストがREDになっていたのでした。
ここでしっかり、" " * 6
と空文字がテストされていたおかげで
自分の勘違いに気づくことができました。。
同じようにうっかりここで詰まってしまった方のご参考になれば幸いです。
##参考