custom error validations

This commit is contained in:
Mark Moser 2016-08-01 09:50:01 -05:00
parent dfd582d251
commit 95eec915c4
11 changed files with 79 additions and 24 deletions

View File

@ -41,7 +41,7 @@ Style/StringLiterals:
Metrics/AbcSize: Metrics/AbcSize:
Exclude: Exclude:
- db/migrate/**/* - db/migrate/**/*
Max: 18 Max: 20
Metrics/LineLength: Metrics/LineLength:
Max: 110 Max: 110

View File

@ -13,8 +13,7 @@ class CandidateController < ApplicationController
end end
def question def question
@status = QuizStatus.new(current_candidate) qid = prep_status.current_question_id
qid = @status.current_question_id
redirect_to :summary and return if qid.nil? redirect_to :summary and return if qid.nil?
@ -29,9 +28,8 @@ class CandidateController < ApplicationController
def summary def summary
@quiz = current_candidate.my_quiz @quiz = current_candidate.my_quiz
@status = QuizStatus.new(current_candidate)
redirect_to :question and return unless @status.current_question_id.nil? redirect_to :question and return unless prep_status.current_question_id.nil?
end end
def update_text def update_text
@ -39,7 +37,7 @@ class CandidateController < ApplicationController
@answer.update(answer: answer_params[:text], @answer.update(answer: answer_params[:text],
saved: answer_params[:save], saved: answer_params[:save],
submitted: answer_params[:next]) submitted: answer_params[:next])
validate_answer route_answer
end end
def update_radio def update_radio
@ -47,7 +45,7 @@ class CandidateController < ApplicationController
@answer.update(answer: answer_params[:radio], @answer.update(answer: answer_params[:radio],
saved: answer_params[:save], saved: answer_params[:save],
submitted: answer_params[:next]) submitted: answer_params[:next])
validate_answer route_answer
end end
def update_checkbox def update_checkbox
@ -55,7 +53,7 @@ class CandidateController < ApplicationController
@answer.update(answer: answer_params[:checkbox], @answer.update(answer: answer_params[:checkbox],
saved: answer_params[:save], saved: answer_params[:save],
submitted: answer_params[:next]) submitted: answer_params[:next])
validate_answer route_answer
end end
def update_live_code def update_live_code
@ -63,7 +61,7 @@ class CandidateController < ApplicationController
@answer.update(answer: answer_params[:live_code], @answer.update(answer: answer_params[:live_code],
saved: answer_params[:save], saved: answer_params[:save],
submitted: answer_params[:next]) submitted: answer_params[:next])
validate_answer route_answer
end end
# TODO # TODO
@ -86,6 +84,10 @@ class CandidateController < ApplicationController
@question = current_candidate.fetch_question(qid) @question = current_candidate.fetch_question(qid)
end end
def prep_status
@status ||= QuizStatus.new(current_candidate)
end
def answer_params def answer_params
params.require(:answer).permit( params.require(:answer).permit(
:question_id, :answer_id, :question_id, :answer_id,
@ -100,10 +102,11 @@ class CandidateController < ApplicationController
answer answer
end end
def validate_answer def route_answer
if @answer.errors.present? if @answer.errors.present?
flash[:error] = [answer_params[:question_id]] prep_status
prep_question answer_params[:question_id] prep_question answer_params[:question_id]
flash[:answer_error] = answer_params[:question_id].to_i
render :question render :question
else else
# TODO: change params.key? to submit = save/next/summary # TODO: change params.key? to submit = save/next/summary

View File

@ -3,4 +3,8 @@ class Answer < ApplicationRecord
belongs_to :question belongs_to :question
belongs_to :candidate belongs_to :candidate
validates :candidate_id, presence: true
validates :question_id, presence: true
validates :answer, answer_format: true
end end

View File

@ -0,0 +1,38 @@
class AnswerFormatValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
send(record.question.input_type, record, attribute, value)
end
private
def text record, attribute, value
return unless value.length.between? 1, 1000
if value.blank?
record.errors[attribute] << (options[:message] || "Please enter an answer.")
end
if value.length > 1000
record.errors[attribute] << (options[:message] || "The character limit for a textarea answer is 1000")
end
end
def radio record, attribute, value
return unless value.nil?
record.errors[attribute] << (options[:message] || "Please select an answer.")
end
def checkbox record, attribute, value
return unless value.nil? || value.join.blank?
record.errors[attribute] << (options[:message] || "Please select an answer.")
end
def live_code record, attribute, value
return unless value.nil?
msg = "You must write code in one of the above textareas to progress."
record.errors[attribute] << (options[:message] || msg)
end
end

View File

@ -0,0 +1,5 @@
<% if flash[:answer_error] == question.question_id %>
<% answer.errors.messages[:answer].each do |message| %>
<div class="error"><%= message %></div>
<% end %>
<% end %>

View File

@ -14,6 +14,4 @@
</div> </div>
<% end %> <% end %>
<% if flash[:error].try(:include?, question.to_i) %> <%= render partial: "candidate/answer_errors", locals: {question: question, answer: @answer} %>
<div class="error">Please select an answer.</div>
<% end %>

View File

@ -9,6 +9,4 @@
</div> </div>
<% end %> <% end %>
<% if flash[:error].try(:include?, question.to_i) %> <%= render partial: "candidate/answer_errors", locals: {question: question, answer: @answer} %>
<div class="error">Please select an answer.</div>
<% end %>

View File

@ -3,6 +3,4 @@
<div class="chars">Characters remaining: <span></span></div> <div class="chars">Characters remaining: <span></span></div>
<% if flash[:error].try(:include?, question.to_i) %> <%= render partial: "candidate/answer_errors", locals: {question: question, answer: @answer} %>
<div class="error">Please select or enter an answer. (The character limit for a textarea answer is 1000)</div>
<% end %>

View File

@ -13,8 +13,6 @@
<textarea data-id="code-js" name="code-js" class="code-answer code-js"><%= @answer['js'] unless @answer.nil? %></textarea> <textarea data-id="code-js" name="code-js" class="code-answer code-js"><%= @answer['js'] unless @answer.nil? %></textarea>
</div> </div>
<% if flash[:error].try(:include?, @question.to_i) %> <%= render partial: "candidate/answer_errors", locals: {question: question, answer: @answer} %>
<div class="error">You must write code in one of the above textareas to progress.</div>
<% end %>
<div class="results" data-id="results"></div> <div class="results" data-id="results"></div>

View File

@ -0,0 +1,5 @@
# TODO: needs better wrapping instead of nuking
# https://rubyplus.com/articles/3401
ActionView::Base.field_error_proc = proc do |html_tag, _instance|
html_tag.html_safe
end

View File

@ -50,5 +50,13 @@ class CandidateControllerTest < ActionDispatch::IntegrationTest
assert_response :success assert_response :success
end end
# should get flash message on bad question test "should get flash message on bad radio response" do
setup_auth candidates(:martha)
qid = questions(:fed1).id
post post_radio_url, params: { answer: { question_id: qid, radio: nil } }
assert_response :success
assert session[:test_id].present?
assert_equal qid, flash[:answer_error]
end
end end