Development
Application Controller Code needed for workspace and status callback
include QualtricsInterface (for example in helpers/shut/study_helper.rb)
Set environment variables
ENV['API_URL'} ||= 'http://api-assessment.bhtcloud.org/'
ENV['QUALTRICS_ID'] = 'a qualtrics api token'
ENV['QUALTRICS_LIBRARY'] = 'a qualtrics library id'
ENV['STUDY_WORKSPACE_NAME'] = 'a unique name for the study on a specific deploy'
Interface
Controller
get_participant_state participant_id, survey_name
- returns 'not started', 'in progress', 'responded'
get_participant_link(participant_id, survey_name)['unique_link']
- returns link to qualtrics
get_results(participant_id, survey_name)['answers']
- returns a hash of question=>respose values
Usage
Participants have activities thru the activity_participants join record. Typical activities are:
interest
consent
phone (phone assessment)
time_1 (pre)
time_2 (post)
time_3 (post_6)
time_4 (post_12)
The survey name referenced in the interface is:
survey_name = ENV['STUDY_WORKSPACE_NAME'] + '-' + activity
#### app/helpers/shuti/study_helper.rb (see git blame for lines 40-70)
There is a horrific method called main_btn_state that governs the appearance
of the big yellow button on the landing page for the intervention.
Here is an extension of that code. Style Notes: the ruby multiple assignment syntax is used:
a,b= something. Obviously this code could be refactored
include QualtricsInterface
def assessment_status assessment_key
main_button=[]
@participant = Participant.find(@participant.id)
assessment_uuid = Activity.find_by(key: assessment_key).uuid
if @participant.assessment_available_or_in_progress?(assessment_key[-1])
survey_name = ENV['STUDY_WORKSPACE_NAME'] + '-' + assessment_key
main_button[0] = activities_path(survey_name: survey_name, activity_uuid: assessment_uuid)
state = get_participant_state(@participant.id, survey_name)
main_button[1] = "#{state == 'not started' ? 'Start' : 'Continue'} #{assessment_key.humanize} Survey"
if state == 'responded'
#STALE CACHE WORKAROUND
raise StaleAASMException unless @participant.activity(assessment_key).in_progress?
@participant.activity(assessment_key).complete!
end
end
[@participant.assessment_available_or_in_progress?(assessment_key[-1]), main_button]
end
def main_btn_state
unless @main_btn_state
@main_btn_state = []
if ['Experimental', 'Control'].include?(@participant.participant_type)
assessment_active, @main_btn_state = assessment_status 'time_4'
return @main_btn_state if assessment_active && @participant.study_phase == 'time_4'
assessment_active, @main_btn_state = assessment_status 'time_3'
return @main_btn_state if assessment_active && @participant.study_phase == 'time_3'
assessment_active, @main_btn_state = assessment_status 'time_2'
return @main_btn_state if assessment_active && @participant.study_phase == 'time_2'
assessment_active, @main_btn_state = assessment_status 'time_1'
return @main_btn_state if assessment_active && @participant.study_phase == 'time_1'
end
#### app/controllers/activities/assessments_controller.rb
The assessment links are accessed by a redirect from the main button state. We redirect to the start route
in the Assesments controller to set the in progress state.
We redirect from Qualtrics to the complete route in order to update the assessment to complete.
class Activities::AssessmentsController < ApplicationController
include QualtricsInterface
prepend_before_action only: [:complete] { request.env["devise.skip_timeout"] = true }
def start
survey_name = params['survey_name']
activity_key = Activity.uuid_to_key(params['activity_uuid'])
participant = current_user.participant
activity = participant.activity(activity_key)
activity.start! unless activity.in_progress?
#STALE CACHE WORKAROUND
raise StaleAASMException unless activity.in_progress?
link = get_participant_link(participant.id, survey_name)['unique_link']
redirect_to link
end
def complete
participant = current_user.participant
activity_key = Activity.uuid_to_key(params['assessment_uuid'])
participant.activity(activity_key).complete!
redirect_to root_path
end
#### app/controllers/activities/consents_controller.rb
The consent links are accessed by a similar controller.
class Activities::ConsentsController < ActionController::Base
include QualtricsInterface
before_action :init_session
def init_session
session[:init] = true
end
def start
uuid=params[:uuid]
survey_name = ENV['STUDY_WORKSPACE_NAME'] + '-' + 'consent'
participant = User.find_by(uuid: uuid).participant
link = get_participant_link(participant.id, survey_name)['unique_link']
activity = participant.activity('consent')
activity.start! unless activity.in_progress?
redirect_to link
end
def complete
CompleteConsentWorker.new.perform
redirect_to consent_thanks_path
end
def download
send_file(
"#{Rails.root}/consent_forms/pid_#{params[:id]}_consent_form.pdf",
filename: "pid_#{params[:id]}_consent_form.pdf",
type: 'application/pdf'
)
end
end
The actual Consent completion process is handled by
###### app/workers/complete_consent_worker.rb The actual Consent completion process invoked by the complete function. This worker synchronously updates the status of the Participant, allowing the study to proceed.
###### app/workers/generate_consent_pdf_worker.rb The Consent form PDF generation invoked with perform_async by the Consent completion worker. It should be possible for this worker to fail and be retried by Sidekiq. When this succeeds it also sends an email with the PDF.
Qualtrics callbacks
The Qualtrics callback for a survey is build with the UUID of an activity. This
callback is found under Survey Options on Qualtrics. Near the bottom of the options
is an option to enter a Redirect URL.
Here's a example for localhost testing.
http://localhost:3000/activities/assessments/complete/045939cd-7ede-47c3-9ae9-3022521c11d
This is routed to a completion endpoint.
which converts that UUID into a activity, like time_1.
Then it updates the status of the current participant.
These UUIDs are in db/seeds/activities.seeds.rb.
Here is what the consent form callback URL looks like for localhost.
http://localhost:3000/activities/consents/complete