rethinking question CRUD
This commit is contained in:
parent
ace9b864d3
commit
dfd582d251
@ -41,7 +41,7 @@ Style/StringLiterals:
|
|||||||
Metrics/AbcSize:
|
Metrics/AbcSize:
|
||||||
Exclude:
|
Exclude:
|
||||||
- db/migrate/**/*
|
- db/migrate/**/*
|
||||||
Max: 27
|
Max: 18
|
||||||
|
|
||||||
Metrics/LineLength:
|
Metrics/LineLength:
|
||||||
Max: 110
|
Max: 110
|
||||||
@ -54,4 +54,4 @@ Metrics/LineLength:
|
|||||||
Metrics/MethodLength:
|
Metrics/MethodLength:
|
||||||
Exclude:
|
Exclude:
|
||||||
- db/migrate/*
|
- db/migrate/*
|
||||||
- app/controllers/*
|
# - app/controllers/*
|
||||||
|
@ -28,4 +28,8 @@ class ApplicationController < ActionController::Base
|
|||||||
def authorize_reviewer
|
def authorize_reviewer
|
||||||
redirect_to review_login_path unless current_reviewer
|
redirect_to review_login_path unless current_reviewer
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def authorize_candidate
|
||||||
|
redirect_to welcome_path unless current_candidate
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,33 +1,30 @@
|
|||||||
class CandidateController < ApplicationController
|
class CandidateController < ApplicationController
|
||||||
|
before_action :authorize_candidate, except: [:welcome, :validate]
|
||||||
|
|
||||||
def welcome
|
def welcome
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def saved
|
||||||
|
end
|
||||||
|
|
||||||
|
def thankyou
|
||||||
|
redirect_to root_path if session[:test_id].nil?
|
||||||
|
reset_session
|
||||||
|
end
|
||||||
|
|
||||||
def question
|
def question
|
||||||
@status = QuizStatus.new(current_candidate)
|
@status = QuizStatus.new(current_candidate)
|
||||||
qid = @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?
|
||||||
|
|
||||||
@question = current_candidate.fetch_question(qid)
|
prep_question qid
|
||||||
@answer = Answer.new
|
@answer = Answer.new
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_answer
|
def live_coder
|
||||||
answer_ids = { question_id: answer_params[:question_id], candidate_id: current_candidate.to_i }
|
question
|
||||||
@answer = Answer.find_or_create_by!(answer_ids)
|
render layout: false
|
||||||
@answer.answer = answer_for_type
|
|
||||||
@answer.saved = answer_params[:save]
|
|
||||||
@answer.submitted = answer_params[:next]
|
|
||||||
|
|
||||||
if @answer.save
|
|
||||||
redirect_to :summary and return if params.key?(:update)
|
|
||||||
redirect_to :saved and return if params.key?(:save)
|
|
||||||
redirect_to :question
|
|
||||||
else
|
|
||||||
flash[:error] = [answer_params[:question_id]]
|
|
||||||
@question = current_candidate.fetch_question(qid)
|
|
||||||
render :question
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def summary
|
def summary
|
||||||
@ -37,50 +34,82 @@ class CandidateController < ApplicationController
|
|||||||
redirect_to :question and return unless @status.current_question_id.nil?
|
redirect_to :question and return unless @status.current_question_id.nil?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def update_text
|
||||||
|
@answer = prep_answer
|
||||||
|
@answer.update(answer: answer_params[:text],
|
||||||
|
saved: answer_params[:save],
|
||||||
|
submitted: answer_params[:next])
|
||||||
|
validate_answer
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_radio
|
||||||
|
@answer = prep_answer
|
||||||
|
@answer.update(answer: answer_params[:radio],
|
||||||
|
saved: answer_params[:save],
|
||||||
|
submitted: answer_params[:next])
|
||||||
|
validate_answer
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_checkbox
|
||||||
|
@answer = prep_answer
|
||||||
|
@answer.update(answer: answer_params[:checkbox],
|
||||||
|
saved: answer_params[:save],
|
||||||
|
submitted: answer_params[:next])
|
||||||
|
validate_answer
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_live_code
|
||||||
|
@answer = prep_answer
|
||||||
|
@answer.update(answer: answer_params[:live_code],
|
||||||
|
saved: answer_params[:save],
|
||||||
|
submitted: answer_params[:next])
|
||||||
|
validate_answer
|
||||||
|
end
|
||||||
|
|
||||||
|
# TODO
|
||||||
def update_summary
|
def update_summary
|
||||||
redirect_to :summary
|
# redirect_to :summary
|
||||||
end
|
|
||||||
|
|
||||||
def thankyou
|
|
||||||
redirect_to root_path if session[:test_id].nil?
|
|
||||||
reset_session
|
|
||||||
end
|
|
||||||
|
|
||||||
def saved
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def validate
|
def validate
|
||||||
candidate = Candidate.find_by(test_hash: params['test_id'])
|
candidate = Candidate.find_by(test_hash: params['test_id'])
|
||||||
|
redirect_to(root_path, alert: "Sorry, incorrect test id") and return if candidate.nil?
|
||||||
|
|
||||||
if candidate.nil?
|
session[:test_id] = candidate.test_hash
|
||||||
reset_session
|
redirect_to :thankyou and return if candidate.completed?
|
||||||
redirect_to root_path, alert: "Sorry, incorrect test id"
|
redirect_to :question
|
||||||
else
|
|
||||||
session[:test_id] = candidate.test_hash
|
|
||||||
redirect_to :question
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def live_coder
|
|
||||||
@question = Question.find(params[:question_id])
|
|
||||||
@answer = @question.answers.order("RAND()").first.answer
|
|
||||||
render layout: false
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def prep_question qid
|
||||||
|
@question = current_candidate.fetch_question(qid)
|
||||||
|
end
|
||||||
|
|
||||||
def answer_params
|
def answer_params
|
||||||
params.require(:answer).permit(
|
params.require(:answer).permit(
|
||||||
:question_id, :answer_id,
|
:question_id, :answer_id,
|
||||||
:save, :next, :summary,
|
:save, :next, :summary,
|
||||||
:radio, :text, checkbox: [], live_coder: []
|
:radio, :text, checkbox: [], live_code: []
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def answer_for_type
|
def prep_answer
|
||||||
return answer_params[:radio] unless answer_params[:radio].nil?
|
answer_ids = { question_id: answer_params[:question_id], candidate_id: current_candidate.to_i }
|
||||||
return answer_params[:text] unless answer_params[:text].nil?
|
answer = Answer.find_or_create_by(answer_ids)
|
||||||
return answer_params[:checkbox] unless answer_params[:checkbox].nil?
|
answer
|
||||||
return answer_params[:live_coder] unless answer_params[:live_coder].nil?
|
end
|
||||||
|
|
||||||
|
def validate_answer
|
||||||
|
if @answer.errors.present?
|
||||||
|
flash[:error] = [answer_params[:question_id]]
|
||||||
|
prep_question answer_params[:question_id]
|
||||||
|
render :question
|
||||||
|
else
|
||||||
|
# TODO: change params.key? to submit = save/next/summary
|
||||||
|
redirect_to :summary and return if params.key?(:update)
|
||||||
|
redirect_to :saved and return if params.key?(:save)
|
||||||
|
redirect_to :question
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
content_for :footer_title, "Skills Assessment"
|
content_for :footer_title, "Skills Assessment"
|
||||||
%>
|
%>
|
||||||
|
|
||||||
<%= form_for(@answer, url: post_answer_path(@answer.id), html:{id: 'answer-form', data: {qid: @question.question_id}}) do |form| %>
|
<%= form_for(@answer, url: send("post_#{@question.input_type}_path", @answer.id), html:{id: 'answer-form', data: {qid: @question.question_id}}) do |form| %>
|
||||||
<main class="questions_tpl">
|
<main class="questions_tpl">
|
||||||
<h2 class="question-text"><%= @question.question %></h2>
|
<h2 class="question-text"><%= @question.question %></h2>
|
||||||
|
|
||||||
|
@ -1,28 +1,31 @@
|
|||||||
Rails.application.routes.draw do
|
Rails.application.routes.draw do
|
||||||
post "/validate", to: "candidate#validate", as: :validate_candidate
|
post "/validate", to: "candidate#validate", as: :validate_candidate
|
||||||
get "/welcome", to: "candidate#welcome", as: :welcome
|
get "/welcome", to: "candidate#welcome", as: :welcome
|
||||||
get "/thankyou", to: "candidate#thankyou", as: :thankyou
|
get "/thankyou", to: "candidate#thankyou", as: :thankyou
|
||||||
get "/saved", to: "candidate#saved", as: :saved
|
get "/saved", to: "candidate#saved", as: :saved
|
||||||
|
|
||||||
post "/question(/:answer_id)", to: "candidate#update_answer", as: :post_answer
|
post "/question/text(/:answer_id)", to: "candidate#update_text", as: :post_text
|
||||||
get "/question(/:question_id)", to: "candidate#question", as: :question
|
post "/question/radio(/:answer_id)", to: "candidate#update_radio", as: :post_radio
|
||||||
get "/live-coder-entry/:question_id", to: "candidate#live_coder", as: :live_coder
|
post "/question/checkbox(/:answer_id)", to: "candidate#update_checkbox", as: :post_checkbox
|
||||||
|
post "/question/live-code(/:answer_id)", to: "candidate#update_live_code", as: :post_live_code
|
||||||
|
get "/question(/:question_id)", to: "candidate#question", as: :question
|
||||||
|
get "/live-coder-entry/:question_id", to: "candidate#live_coder", as: :live_coder
|
||||||
|
|
||||||
post "/summary", to: "candidate#update_summary", as: :post_summary
|
post "/summary", to: "candidate#update_summary", as: :post_summary
|
||||||
get "/summary", to: "candidate#summary", as: :summary
|
get "/summary", to: "candidate#summary", as: :summary
|
||||||
|
|
||||||
get "/review/logout", to: "review#logout", as: :review_logout
|
get "/review/logout", to: "review#logout", as: :review_logout
|
||||||
post "/review/login", to: "review#auth", as: :review_auth
|
post "/review/login", to: "review#auth", as: :review_auth
|
||||||
get "/review/login", to: "review#login", as: :review_login
|
get "/review/login", to: "review#login", as: :review_login
|
||||||
get "/review", to: "review#index", as: :review
|
get "/review", to: "review#index", as: :review
|
||||||
get "/review/:test_hash", to: "review#view", as: :review_test
|
get "/review/:test_hash", to: "review#view", as: :review_test
|
||||||
|
|
||||||
get "/recruiter", to: "recruiter#index", as: :recruiter
|
get "/recruiter", to: "recruiter#index", as: :recruiter
|
||||||
get "/recruiter/new-candidate", to: "recruiter#new", as: :new_candidate
|
get "/recruiter/new-candidate", to: "recruiter#new", as: :new_candidate
|
||||||
post "/recruiter/new-candidate", to: "recruiter#create", as: :create_candidate
|
post "/recruiter/new-candidate", to: "recruiter#create", as: :create_candidate
|
||||||
get "/recruiter/logout", to: "recruiter#logout", as: :recruiter_logout
|
get "/recruiter/logout", to: "recruiter#logout", as: :recruiter_logout
|
||||||
get "/recruiter/login", to: "recruiter#login", as: :recruiter_login
|
get "/recruiter/login", to: "recruiter#login", as: :recruiter_login
|
||||||
post "/recruiter/login", to: "recruiter#auth", as: :recruiter_auth
|
post "/recruiter/login", to: "recruiter#auth", as: :recruiter_auth
|
||||||
|
|
||||||
root to: "candidate#welcome"
|
root to: "candidate#welcome"
|
||||||
|
|
||||||
|
@ -6,4 +6,12 @@ select c.id candidate_id
|
|||||||
from candidates c
|
from candidates c
|
||||||
inner join questions q on q.quiz_id = c.quiz_id
|
inner join questions q on q.quiz_id = c.quiz_id
|
||||||
left join answers a on a.candidate_id = c.id AND a.question_id = q.id
|
left join answers a on a.candidate_id = c.id AND a.question_id = q.id
|
||||||
|
|
||||||
|
where c.test_hash = 'R67PmfDHGiw' -- and q.input_type = 'radio'
|
||||||
|
|
||||||
order by c.name, q.sort;
|
order by c.name, q.sort;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- delete from answers where id = 1008398109
|
||||||
|
|
||||||
|
54
test/controllers/candidate_controller_test.rb
Normal file
54
test/controllers/candidate_controller_test.rb
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
class CandidateControllerTest < ActionDispatch::IntegrationTest
|
||||||
|
def setup_auth candidate
|
||||||
|
post validate_candidate_url, params: { test_id: candidate.test_hash }
|
||||||
|
end
|
||||||
|
|
||||||
|
test "should get login" do
|
||||||
|
get welcome_path
|
||||||
|
assert_response :success
|
||||||
|
end
|
||||||
|
|
||||||
|
test "should require auth or redirect" do
|
||||||
|
get saved_path
|
||||||
|
assert_redirected_to welcome_path
|
||||||
|
|
||||||
|
get thankyou_path
|
||||||
|
assert_redirected_to welcome_path
|
||||||
|
|
||||||
|
get summary_path
|
||||||
|
assert_redirected_to welcome_path
|
||||||
|
|
||||||
|
get question_path
|
||||||
|
assert_redirected_to welcome_path
|
||||||
|
|
||||||
|
get question_path(questions(:fed1).id)
|
||||||
|
assert_redirected_to welcome_path
|
||||||
|
|
||||||
|
get live_coder_path(questions(:fed1).id)
|
||||||
|
assert_redirected_to welcome_path
|
||||||
|
end
|
||||||
|
|
||||||
|
test "should auth to question" do
|
||||||
|
setup_auth candidates(:martha)
|
||||||
|
|
||||||
|
assert_redirected_to question_path
|
||||||
|
assert session[:test_id].present?
|
||||||
|
end
|
||||||
|
|
||||||
|
test "should redirect to thankyou when completed" do
|
||||||
|
setup_auth candidates(:richard)
|
||||||
|
|
||||||
|
assert_redirected_to thankyou_path
|
||||||
|
end
|
||||||
|
|
||||||
|
test "should get summary if complete but not submitted" do
|
||||||
|
setup_auth candidates(:dawn)
|
||||||
|
|
||||||
|
get summary_url
|
||||||
|
assert_response :success
|
||||||
|
end
|
||||||
|
|
||||||
|
# should get flash message on bad question
|
||||||
|
end
|
8
test/fixtures/answers.yml
vendored
8
test/fixtures/answers.yml
vendored
@ -39,7 +39,7 @@ dawn2:
|
|||||||
dawn3:
|
dawn3:
|
||||||
candidate: dawn
|
candidate: dawn
|
||||||
question: fed3
|
question: fed3
|
||||||
answer: {html: "<h1>I'm a little tealpot</h1>", css: 'h1 {color: teal;}', js: ''}
|
answer: {html: "dawn3 <h1>I'm a little tealpot</h1>", css: 'h1 {color: teal;}', js: ''}
|
||||||
saved: 0
|
saved: 0
|
||||||
submitted: true
|
submitted: true
|
||||||
created_at: <%= DateTime.now() - 38.hours - 50.minutes %>
|
created_at: <%= DateTime.now() - 38.hours - 50.minutes %>
|
||||||
@ -75,7 +75,7 @@ dawn6:
|
|||||||
dawn7:
|
dawn7:
|
||||||
candidate: dawn
|
candidate: dawn
|
||||||
question: fed7
|
question: fed7
|
||||||
answer: {html: '<p>This means <strong>jQuery</strong> needs to be available in live-coder!</p>', css: "strong {font-size: 1.6em;}\n.green {color: green;}", js: '$("strong").addClass("green");'}
|
answer: {html: 'dawn7 <p>This means <strong>jQuery</strong> needs to be available in live-coder!</p>', css: "strong {font-size: 1.6em;}\n.green {color: green;}", js: '$("strong").addClass("green");'}
|
||||||
saved: 0
|
saved: 0
|
||||||
submitted: true
|
submitted: true
|
||||||
created_at: <%= DateTime.now() - 38.hours - 34.minutes %>
|
created_at: <%= DateTime.now() - 38.hours - 34.minutes %>
|
||||||
@ -129,7 +129,7 @@ richard2:
|
|||||||
richard3:
|
richard3:
|
||||||
candidate: richard
|
candidate: richard
|
||||||
question: fed3
|
question: fed3
|
||||||
answer: {html: '<h1>Salmon</h1>', css: 'h1 {color: salmon;}', js: ''}
|
answer: {html: 'richard3 <h1>Salmon</h1>', css: 'h1 {color: salmon;}', js: ''}
|
||||||
saved: 0
|
saved: 0
|
||||||
submitted: true
|
submitted: true
|
||||||
created_at: <%= DateTime.now() - 36.hours - 26.minutes %>
|
created_at: <%= DateTime.now() - 36.hours - 26.minutes %>
|
||||||
@ -165,7 +165,7 @@ richard6:
|
|||||||
richard7:
|
richard7:
|
||||||
candidate: richard
|
candidate: richard
|
||||||
question: fed7
|
question: fed7
|
||||||
answer: {html: '<p>This means <strong>jQuery</strong> needs to be available in live-coder!</p>', css: "strong {font-size: 1.6em;}\n.green {color: green;}", js: '$("strong").addClass("green");'}
|
answer: {html: 'richard7 <p>This means <strong>jQuery</strong> needs to be available in live-coder!</p>', css: "strong {font-size: 1.6em;}\n.green {color: green;}", js: '$("strong").addClass("green");'}
|
||||||
saved: 0
|
saved: 0
|
||||||
submitted: true
|
submitted: true
|
||||||
created_at: <%= DateTime.now() - 36.hours - 34.minutes %>
|
created_at: <%= DateTime.now() - 36.hours - 34.minutes %>
|
||||||
|
4
test/fixtures/questions.yml
vendored
4
test/fixtures/questions.yml
vendored
@ -22,7 +22,7 @@ fed3:
|
|||||||
quiz: fed
|
quiz: fed
|
||||||
question: How would you create a widget that would fit in a 250px wide area as well as a 400px wide area?
|
question: How would you create a widget that would fit in a 250px wide area as well as a 400px wide area?
|
||||||
category: CSS
|
category: CSS
|
||||||
input_type: live-coder
|
input_type: live_code
|
||||||
input_options:
|
input_options:
|
||||||
sort: 2
|
sort: 2
|
||||||
active: true
|
active: true
|
||||||
@ -58,7 +58,7 @@ fed7:
|
|||||||
quiz: fed
|
quiz: fed
|
||||||
question: Provide a code example to manipulate the DOM using jQuery/JavaScript to change the classname of a div 'classB' to 'classC', only if the div 'classA' exists in the page?
|
question: Provide a code example to manipulate the DOM using jQuery/JavaScript to change the classname of a div 'classB' to 'classC', only if the div 'classA' exists in the page?
|
||||||
category: Javascript
|
category: Javascript
|
||||||
input_type: live-coder
|
input_type: live_code
|
||||||
input_options:
|
input_options:
|
||||||
sort: 6
|
sort: 6
|
||||||
active: true
|
active: true
|
||||||
|
Loading…
Reference in New Issue
Block a user