Skip to content

jjcucb/moocchat

 
 

Repository files navigation

MOOCchat is a SaaS app for integrating peer learning/peer discussion into MOOCs and similar settings.

This document gives an overview of how to set up experiments/activities with MOOCchat. Partial URLs are given for all paths, so that if the app is hosted on http://moocchat.herokuapp.com, the path /tasks/welcome refers to http://moocchat.herokuapp.com/tasks/welcome.

User Roles:

  • A Learner is a person in a course who participates in peer instruction activities.

  • A Cohort is a group of learners, e.g., the enrollees in a course. A learner can belong to multiple cohorts.

  • An Instructor is an instructional staff member or researcher who sets up peer instruction activities and can also do anything a Learner can do (for example, test-drive an activity).

  • An Administrator administers the use of the system and can also do everything that Learners and Instructors can do.

Objects:

A Question is an opportunity for a learner to respond to something, via multiple choice, open ended text, or whatever.

An Activity Schema is a list of Questions that may feature some peer instruction, for example, a quiz review session.

A Condition describes how a learner or group of learners interacts with an Activity Schema (set of questions). The Condition consists of a set of page views based on Templates. Specifically, a condition consists of:

  • a sequence of zero or more prologue pages (e.g., instructions to the

learner)

  • a sequence of one or more body pages

  • a repeat count for the number of times the body sequence is to be repeated

  • a sequence of zero or more epilogue pages.

Each template in the body can specify whether to advance the question counter or not, to consume successive questions from the Activity Schema. It is the experimenter’s responsibility to ensure there are enough questions. For example, suppose the body contains two pages, each page consumes a question, and the body is to be repeated five times. Then the Activity Schema should contain at least ten questions to avoid repetition. (The question counter will wrap around to the beginning of the question list if it runs out of questions.)

Templates should be complete legal HTML 5 pages. At the moment, we store the raw HTML of the pages verbatim, so you can author your templates in whatever environment you want and then cut-and-paste the HTML. You can incorporate inline CSS styles in the template, or use a <link> element to point to an external stylesheet.

**HOWEVER, IT IS VERY IMPORTANT** that every template include the following inside the head element:

<%= javascript_include_tag "application" %>

This will ensure the page loads the JavaScript functions that allow the timer and other interactions to work.

Templates are processed through erb, which allows the values of Ruby variables and expressions to be interpolated into the HTML. The notation <%= expr %> evaluates the Ruby expression expr and inserts the result into the HTML template.

Non-Rubyists may find it helpful to know that Ruby instance variable names begin with @.

Most templates will have a timer element that automatically advances to the next page if the learner hasn’t manually done so when the timer runs out.

Therefore, when a template is first displayed to the learner, the element with the HTML5 element id interstitial (if one exists) is immediately hidden; if the learner advances to the next page before the timer runs out, this element is revealed, so it should display a message to the effect that “You’ll proceed to the next step as soon as all learners in your group are ready.” You can use CSS to float the element in a lightbox, overlay it on top of the main HTML, or whatever.

Below is a line-numbered example of the <body> of a template keyed to the following explanation. Line numbers are in parentheses.

(1) @start_form_tag

A complete <form> tag to start the form whose submission will cause the learner to move on to the next part of the task. See the next subsection on Learner Navigation. Do not try to construct the <form> tag manually.

(3) @question

The text of the current question. In practice you’d probably put this in a properly-styled div.

(6) @answers

An array of strings representing the possible answers; you can iterate over it with each or each_with_index. @correct_answer_index is the zero-based index of which answer is the correct one.

(7, 11) @u

A hash that stores any user-defined state information associated with *this learner*; you can name elements of this hash in your forms to cause data to be collected or displayed. Only form fields named u[...] will be persisted and logged.

(23) timer

A macro that creates a JavaScript countdown timer. By default it will count down from @timer seconds, which is set from the experimental condition, and on reaching zero, it will cause the form-submit button on the page’s single form to be “clicked”. Both of these default behaviors can be overridden; see the TemplateHelper#timer documentation.

 1 <%= @start_form_tag %>
 2   <p>Here is a question:</p>
 3       <%= @question %>
 4   <p>Select the best answer:</p>
 5     <!-- capture learner's answer as choice number, 0..n-1  -->
 6     <% @answers.each_with_index do |answer, index| %>
 7       <input type="radio" value="<%= index %>" name="u[response]"> <%= answer %>
 8     <% end %>
 9   <!-- optional: collect free-text explanation from learner -->
10   <p>Please explain your answer (will be seen by instructor)</p>
11   <input type="textarea" name="u[explanation]"> <br>
12   <!-- timer - by default, countdown specified by Condition -->
13   <%= timer %>
14   <!-- submit button - automatically "clicked" if timer expires first -->
15   <input type="submit" value="Ready to Continue">
16 </form>
(3) @data

An _array of hashes_, where each element is a hash of one learner’s user data (collected by form fields named u[...]). Here it’s used to display what answers and explanations the other learners gave; its keys are the same as those you specified as in lines 7 and 11 in the previous example.

(4) @me

The index of the array corresponding to this learner. @u['foo'] is therefore a synonym for @data[@me]['foo']. *BUT (important)* to persist collected data, you must use form fields named u[...].

(10) chat

A macro that shows a chat window that is “listening” to the chat channel @chat_group.

TBD

If learners all click Request to End Chat, this should override the timer-based form submission and allow everyone to proceed. This will

 require modifying the +page+  method to check that all learners in the
 task are on the same page.

 1 <%= @start_form_tag %>
 2   <p>Here are the answers your peers gave:</p>
 3   <% @data.each_with_index do |other, index| %>
 4     <% next if index == @me %>
 5     <p>Student <%= index %> selected choice <%= other['response'] %> because:</p>
 6     <p> <%= other['explanation'] %>
 7   <% end %>
 8   <!-- chat room -->
 9   <p>Discuss with others until time runs out or you're ready to go on :</p>
10   <%= chat %> 
11   <%= timer %>  
12   <input type="submit" value="Request to end chat">  
13 </form>
(3) @correct_answer_index

Numerical index into the array of answers.

(5) next_question

If this hidden field is present and has any nonblank value, the question counter will be advanced to cause the next question to be consumed. You would use this if a single pass through the activity involves answering more than one question, for example, a basic question followed by a transfer question.

1 <%= @start_form_tag %>
2   <p>The correct answer was:</p>
3   <%= @answers[@correct_answer_index] %>
4   <!-- make next page in flow advance to the next question -->
5   <input type="hidden" name="next_question" value="true">
6 </form>

The relevant controller actions in TasksController are:

static (GET)

Serve a static page that lets learner choose activity and condition from menus. Used primarily for testing.

create (POST)

Create a new Task from a learner name, Condition (experimental setup specifying page flow, group sizes, time spent on each page, and so on) and ActivitySchema (list of questions to be used in the task). Also adds the task to a WaitingRoom with other learners assigned to the same condition and activity. The ActivitySchema specifies how often the waiting room is “emptied”.

welcome (GET)

A successful POST to create results in a redirect to the welcome action, which shows a timer that counts down to when this waiting room is to be emptied. On expiration, a POST to first_page occurs.

join_group (POST)

processes the waiting room, so that every Task in the waiting room gets assigned to a chat_group. If the value of chat_group is the same as the value of the constant WaitingRoom::CHAT_GROUP_NONE, then there weren’t enough waiting learners to fill out the minimum group size specified by the Condition, and this learner is redirected to sorry and asked to retry the activity later. Otherwise, the learner is redirected to page, a generic endpoint that will be called to render the next template in the flow.

page

sets up all the variables described under Templates, above, and renders the page. Most templates will have a timer. Advancing past the current page, whether manually by clicking the Submit button or automatically on timer expiration, results in a POST to next_page, which advances the page counter and then redirects back to page. As described above, the presence of the next_question hidden form element determines whether the next usage of @question (and its corresponding @answers) will use the same question or a new one. The body portion of the condition will be repeated while questions remain. This action is idempotent: reloading a page while in this state has no effect.

sorry

A dead-end page that asks the learner to come back later, since they couldn’t be placed into a chat group.

These will be less frequently used but are listed here for completeness.

@task_id

an identifier for a data structure that associates a specific Learner, Condition, and Activity Schema, and stores all state related to that learner. Useful to display for debugging purposes.

@counter

an integer tracking the page number in the overall activity, starting from 1 for the first prologue page. For example, a task with 1 prologue page, 2 epilogue pages, and a 4-page sequence for each of three questions has 12(3*4)=15 total pages, so counter values will range from 1 to 15.

@subcounter

a zero-based counter tracking the page number within the current sequence (prologue, body, epilogue). E.g., for the preceding example, its successive values would be 0, 0,1,2,3, 0,1,2,3, 0,1,2,3, 0,1.

@where

one of the three strings prologue, body, or epilogue, indicating where we are in the current condition. Can be used, e.g., in conjunction with @subcounter and/or @task_id to style page elements accordingly by giving them CSS classes based on these variables’ values, as in <body class=<%= @where “-” @subcounter %>>‘, giving class names such as prologue-0, body-2, etc.

@chat_group

a string that identifies the chat group this learner is in; think of it as a channel. After the Welcome page of the task, this is guaranteed to be nonblank (the learner could be in a chat group of size 1, but she will definitely be in some group).

Every interesting “event” is logged in a table from which log information can be easily extracted as JSON or CSV. Some events are logged at the server side; for events detected at the client side, TasksController#log_event can receive a POST (from whose URL the ID of the task can be determined) and will look for fields name (required) and value (optional since not all events use it) to create and log the event, and return a 200 OK if all goes well.

Each row of the table has the following attributes:

created_at

When this event was logged, to the nearest second in UTC.

task_id, learner_id, activity_schema_id, condition_id

Foreign keys to the corresponding entities associated with the event.

counter, subcounter, question_counter

Current values of the counter (overall page in the task, 0-based), subcounter (subpage within prologue/body/epilogue), question counter (how many questions have been consumed so far)

question_id

The ID of the current question pointed to by the question counter (whether or not the question is displayed on the current page)

chat_group

For all events where the learner is already associated with a chat group (typically, any except start and reject), the chat group channel name.

name, value

name is a lower_snake_case string indicating what event happened. A few events also have a string value, as indicated below; for events with no value, the value column is blank:

  1. start start new activity

  2. reject learner must quit since not enough other learners to chat),

  3. abandon voluntarily abandonment of task (closed browser, etc.) - assuming we can reliably detect

  4. broken_pipe involuntary abandonment of task, eg network failure - assuming we can reliably detect

  5. form_group get placed in a chat group

  6. continue learner clicks “Continue”; value of counter field is which page in task (starting from 0 for first prologue page) she was continuing from

  7. view_page after clicking Continue and waiting for peers, learner is served the next page. Typically a continue event with counter value n would be followed shortly after by a proceed event with counter value n+1.

  8. finish complete activity by exiting from its final page

  9. user_data Sets value to “key,new_data”: learner modifies user data in any way, even while still on page. Since user data is a set of key-value pairs per user, if the learner modifies multiple data items, an event will be logged for each modified item. The key is guaranteed not to contain commas, so splitting this string on the first comma will always reconstruct the original key and new_data.

  10. chat: sets value to what this user just typed in chat box

  11. quit_chat vote to stop chatting

  12. rejoin_chat undo (cancel) a previous vote to stop chatting

About

SaaS app for integrating peer learning/peer discussion into MOOCs and similar settings

Resources

License

Stars

0 stars

Watchers

1 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • Ruby 79.3%
  • JavaScript 18.3%
  • CSS 1.6%
  • CoffeeScript 0.8%