Skip to content

Instantly share code, notes, and snippets.

@jfinucane
Created August 30, 2017 20:50
Show Gist options
  • Save jfinucane/473f346bd32e75ebb7867bcf3430abea to your computer and use it in GitHub Desktop.
Save jfinucane/473f346bd32e75ebb7867bcf3430abea to your computer and use it in GitHub Desktop.
Qualtrics documentation

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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment