パンがなければおかs(ry
####特定paramのValidationをskipしたい時?
Userモデルが:name, :email, :password
などを持っていて、各項目にValidationしたい。
でもログインしてるユーザが:name
だけを変更する時に毎回パスワードを入力させたくない、と言った場合があるかと思います。
@user.update_attributes(params[:user])
とすると、param[:user][:password]がなくても全体に対するValidationが走ってしまい、エラーとなります。
@user.update_attribute( :name, "new name" )
とすればvalidationを行わずに更新できますが、それでは:name
のvalidationが出来ません。
またvalidates :password, presence: { on: :create }
とすれば特定のactionでのみvalidationが走りますが、update時にもvalidateしたいので却下でした。
####Grouping conditional validations
という訳でwith_options
を使う方法に行き着きました。
with_options if: 'password || new_record?' do |user|
user.validates :password, presence: true,
length: { minimum: 6 },
confirmation: true
user.validates :password_confirmation, presence: true
end
:password
のパラメータがあればvalidationを行い、無ければスルーします。
追記:
元々if: :password
だけの条件にしていましたが、これだと会員登録画面でパスワードフォームを削除するとパスワードのValidationをスキップしてしまう、と言う状態になっていました。DBでnull: falseとか指定していれば問題ないんですが、モデルの仕事が出来てない感があるのでif: 'password || new_record?'
としました。
これで「password
パラメータがあればvalidationを行い、無ければスルー。但し新規作成時は必ずvalidationを行う」と言う条件になります。
コピペして使うとマズいコード載せてたんだな…と戦犯気分の午後でした。
:追記ここまで
検索して見つかった解決法の中ではこれが一番しっくり来るかなぁと思うのですが、他にもいい方法ありそう。
参考:
Grouping conditional validations
Rails 3 validates rule based on action
Rails Override Save To Perform Selective Update
railsのバリデーションに今さら喧嘩を売る