2017-09-04 5 views
0

ユーザーが正しいSMSコードを入力したかどうかを確認するカスタムバリデータがあります。ユーザーが間違ったコードを入力すると、失敗した試行をログに記録し、コードごとに3回の再試行を制限する必要があります。バリデータ内のインクリメントフィールド

フィールドがインクリメントされていない次のバリデータを作成しました。

def token_match 
    if token != User.find(user_id).verification_token 
     User.find(user_id).increment!(:verification_fails) 
     errors.add(:sms_code, "does not match") 
    end 
    end 

エラーは、前のステートメントがロールバックされるとすぐに問題になります。 errors.add行をコメントアウトするとインクリメントは機能しますが、上位レベルの検証は実行されません。

+0

あなたがバリデータを乱用しています。このチェックには使用しないでください。モデルの簡単な方法を使用してください。 – meagar

+0

ありがとうございます。レコードを保存する前にビジネスロジックを満足させる必要がある場合はどうすればよいですか?必要な唯一の妥当性検査は存在です:しかし、ユーザーが既に3回失敗した場合、レコードは更新されません。 – Dercni

答えて

0

バリデーターに#update_columnsを使用できます。 dbに直接書き込みます。

u = User.find(user_id) 
u.update_columns(verification_fails: u.verification_fails + 1) 

これは私のために働いた。

Thread.new do 
    num = User.find(user_id).verification_fails 
    ActiveRecord::Base.connection_pool.with_connection { |con| con.exec_query("UPDATE users SET verification_fails = #{num} WHERE id = #{user_id}") } 
end.join 
+0

動作しませんでした。エラーコレクションにメッセージを追加すると、update_columnがロールバックされます。 – Dercni

+0

私の答えを更新しました。それが役に立てば幸い。 – EJ2015

0

変更カスタムバリデータがする:いくつかの理由で、それはあなたのために動作しない場合でも、多分あなたは新しいDB接続を作成する新しいスレッド、それを実行してみることができます

def token_match 
    if token != User.find(user_id).verification_token 
     errors.add(:sms_code, "does not match") 
    end 
    end 

とこのようになり、あなたのモデルにafter_validationコールバックを追加します。

after_validation: increase_fails_count 

    def increase_fails_count 
     unless self.errors[:sms_code].empty? 
     user = User.find_by(:id => user_id) 
     user.increment!(:verification_fails) 
     user.save 
     end 
    end 
+0

は、after_validationコールバックを使用してもロールバックされます – Dercni

+0

@Dercni私の改訂された回答に従って明示的にuser.saveを呼び出そうとします –

+0

トリガー検証を再度保存しませんか? – EJ2015

関連する問題