以下の書籍でログイン機能を作ってたとき、2時間くらいハマりました。。。あとで「何だっけ?」となったときに思い出せるようにメモしておきます。
ちなみに、このやり方は古いようで、最近は暗号化も含めて簡単に記述(has_secure_password)できるようなので、Rails勉強中の方にとってはノイズになりますので、この記事はくれぐれも無視してください。
改訂3版基礎 Ruby on Rails (KS IMPRESS KISO SERIES)
- 作者: 黒田努,佐藤和人,株式会社オイアクス
- 出版社/メーカー: インプレス
- 発売日: 2015/05/22
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (2件) を見る
ログインするユーザを登録するときに、パスワードの入力誤りを防止するために2回入力させることがよくありますが、それを実装します。
Userモデル(name:string、hashed_password:string)に基本情報をいれます。テーブルにはハッシュ後のパスワードをいれるため、モデルにない項目を入力フォームで扱う必要があります。これはこれで勉強になります。
モデルに項目を追加するため、普通のRuby同様に、attr_accessorで定義します。あと、passwordのセッターを定義しておいて、passwordに代入された文字列を横取りして、テーブルに入れるパスワードを暗号化するメソッドを追加します。いたって普通です。
attr_accessor :password, :password_confirmation def password=(val) if val.present? self.hashed_password = BCrypt::Password.create(val) end @password = val end
さらに、Userモデルに以下のvalidatesを追加します。
validates :name, presence: true, uniqueness: true validates :password, presence: true, length: {minimum: 4}, confirmation: true
さらに、コントローラのcreateアクションを以下のようにしました。
def create @user = User.new(name: params[:user][:name], password: params[:user][:password]) if @user.save redirect_to users_path else
で、この状態でユーザ登録すると、なぜかパスワードが確認用のパスと一致していなくても通過しちゃうんですね。。。ここから調べること2時間。。。もったいない。ほんと。
原因はコントローラの書き方でした。
上記の書籍ではストロングパラメタを使っているので私のようなことは起きません。私は学習を用意にするため、記述は面倒ですが、ストロングパラメタを使わず、1つずつビューから渡す記述をしていたんですね。。。
本来であれば、以下のように書くべきなんですね。めちゃくちゃ長くなってどうにもこうにもッテ感じがしますが、バリデーションする元ネタであるpassword_confirmationをUserモデルにセットしていなかった。。。ここがミスでした。
def create @user = User.new(name: params[:user][:name], password: params[:user][:password], password_confirmation: params[:user][:password_confirmation]) if @user.save redirect_to users_path else
それでも、validatesを記述しているんだから不一致のチェックくらいしてくれたら。。。と思うのですが、「password_confirmationがnilの場合は同一性のチェックは行わない」という仕様なんだそうです。確かにドキュメントに書いてあったような気がします。読み飛ばしてしまいましたが。。。そのため気づくのが遅れてしまったわけです。
password_confirmationが空かどうかもバリデーションすべきってことです。それで気づけたのかもしれません。Userモデルにその記述を追加すると以下のようになります。
validates :name, presence: true, uniqueness: true validates :password, presence: true, length: {minimum: 4}, confirmation: true validates :password_confirmation, presence: true
2時間返して。。。