たとえば以下のような役割分担でパスワード変更画面を作るとします。
+ パスワードの書式はmodel側で、validates_xxx_ofを使ってチェックする
+ 旧パスワードが登録されているものと一致しているかはcontrollerでチェックする
この場合、modelとcontrollerのエラーをひとつにまとめて見せたいとしたら、どうやるのがエレガントなのでしょうか。
私のコードのままでもControllerの
@user.current_password_check_required = true
の代わりに
@user.current_password ||= ''
と書き、current_passwordにnilが入っていた場合に、''を代入しチェックを有効にする事ができます。どうでしょ?
旧パスワードのチェックをModelでやらせるのはどうでしょうか?
コードが出てないので、ちょっと具体的には分かりませんが、その辺だけでも切り出せませんか?
使っているModelは、login_generatorのapp/models/user.rbそのままです。(http://d.hatena.ne.jp/pekeq/20060518/p1にソースを貼っておきます)
このModelには、User#change_passwordというメソッドがあるにはあるのですが、このメソッドを使ってパスワードを変更してしまうと、validates_xxx_ofに書いてあるチェックが効かないのです。
じゃあ、modelにcurrent_passwordとかいうアクセサを定義して、validate_on_updateでcurrent_passwordと現在のパスワードが一致しているかをチェックすればいいかと思ったんですが、そうすると他の要素(例えばログイン名)を変更する際にもcurrent_passwordを定義してやらねばならないので、これはこれで困りものです。
じゃあやっぱりcontrollerで、変更前のパスワードをチェックして、@user.saveでvalidatorのチェックをするしかないかなー、というのでこの質問になりました。
* 追記
http://d.hatena.ne.jp/pekeq/20060518/p1に、modelとcontrollerのエラーをひとつにまとめて見せたいコードの例を載せました。
Userモデルにこれを追加するのはどうでしょう?
パスワードを変更したい場合はchange_passwordを使わず、普通にセットするだけで大丈夫です。
また、current_passwordに何かセットした場合のみ、変更前のパスワードと一致するか、チェックする事ができます。
class User
attr_accessor :current_password
after_validate :crypt_password
〜〜
def crypt_password
old_date = User.find(self.id)
return if old_date && self.password == old_date.password
update_attribute "password", self.class.sha1(self.password)
end
def validate
return true if @current_password.nil?
errors.add(:current_password, "を正しく入力してください") unless User.find(self.id).password == @current_password
end
end
ありがとうございます。
でもこれだと、current_passwordを空欄にしてsubmitすると、パスワード変更ができてしまいますよね。そうすると、やっぱりcontroller側でのチェックをしないといけなくなってしまうのではないでしょうか。
要件がはっきりしてないのがいけないですね。
- 入力項目のチェックが全部model側でできるのがベスト
- パスワード変更時は、「current_passwordが入力されている」「current_passwordが変更前パスワードと一致している」「password, password_confirmationが一致している」「passwordがvalidaterで記述した書式と一致している」ことをmodel側で確認したい
- 一方で、Userモデルのその他の要素(loginなど)を変更する場合は、current_passwordの入力チェック・パスワードチェックは不要
- パスワード変更も、その他要素の変更も、User#saveで行えればベスト
…と、ここまで書いて思いましたが、Model側でやるなら、こういう実装にすればいいかもしれないですね。
1. current_password_check_requiredとかいうフラグ変数をattr_accessorで用意しておく
2. controller側からフラグをセット
3. validateの中で、フラグが立っていたらcurrent_passwordの入力チェック、認証チェックをする
(あんまり格好良くないけど)
* 追記
私なりに書いてみたコードをhttp://d.hatena.ne.jp/pekeq/20060519/p1に載せてみました。
私のコードのままでもControllerの
@user.current_password_check_required = true
の代わりに
@user.current_password ||= ''
と書き、current_passwordにnilが入っていた場合に、''を代入しチェックを有効にする事ができます。どうでしょ?
なるほど。これはかっこいいですね。
頂いた内容で、controller側にチェックロジックを持たなくてもよくなったので、質問を終了します。
masuidriveさん、おつきあい頂いてありがとうございました。
なるほど。これはかっこいいですね。
頂いた内容で、controller側にチェックロジックを持たなくてもよくなったので、質問を終了します。
masuidriveさん、おつきあい頂いてありがとうございました。