人力検索はてな
モバイル版を表示しています。PC版はこちら
i-mobile

Ruby on Railsで、controllerとmodel両方のエラーをうまく扱う方法を教えてください。
たとえば以下のような役割分担でパスワード変更画面を作るとします。

+ パスワードの書式はmodel側で、validates_xxx_ofを使ってチェックする
+ 旧パスワードが登録されているものと一致しているかはcontrollerでチェックする

この場合、modelとcontrollerのエラーをひとつにまとめて見せたいとしたら、どうやるのがエレガントなのでしょうか。

●質問者: pekeq
●カテゴリ:コンピュータ
✍キーワード:Model Ruby on Rails いるか ひとつ エラー
○ 状態 :終了
└ 回答数 : 4/4件

▽最新の回答へ

1 ● masuidrive
●0ポイント

旧パスワードのチェックを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のエラーをひとつにまとめて見せたいコードの例を載せました。


2 ● masuidrive
●0ポイント

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に載せてみました。


3 ● masuidrive
●0ポイント

先ほどのコードにミスありました。

after_validate -> after_validation

でお願いします。


4 ● masuidrive
●486ポイント ベストアンサー

私のコードのままでもControllerの

@user.current_password_check_required = true

の代わりに

@user.current_password ||= ''

と書き、current_passwordにnilが入っていた場合に、''を代入しチェックを有効にする事ができます。どうでしょ?

◎質問者からの返答

なるほど。これはかっこいいですね。

頂いた内容で、controller側にチェックロジックを持たなくてもよくなったので、質問を終了します。

masuidriveさん、おつきあい頂いてありがとうございました。

関連質問


●質問をもっと探す●



0.人力検索はてなトップ
8.このページを友達に紹介
9.このページの先頭へ
対応機種一覧
お問い合わせ
ヘルプ/お知らせ
ログイン
無料ユーザー登録
はてなトップ