CSC/ECE 517 Fall 2013/final E911 rmsa
E722 - A module to take reports from students on results of interactions with helpers from other groups.
Description
Interaction feature allows students to enter information about their interaction with other students when they worked on projects. So this information helps the instructors of the course and TAs of that course to assign extra credit based n how well they interacted with each other and how well did one help its colleagues with their questions in the project.
The views and corresponding code help
When you login as an instructor, you can view the questionnaires. The questionnaire listing will have a questionnaire named Interaction Review.
Creating an interaction review
You can then add a public or private Interaction Review. While creating interaction review you must add questions that you wish to be added in the questionnaire and mention their scores and their weight.
Editing an interaction review
After creating the interaction review, you can see it by clicking on Questionnaires --> Interaction Review
You can then edit advice for each of the questions that you added in the Interaction Review Questionnaire.
Editing an assignment to assign weight and score cap for Interaction Review
After creating the interaction review and its questions and advice, it is now necessary to set a score cap and extra credit percentage for the interaction review for that assignment.
Since, interaction review comes under extra credit we have to set the extra credit percentage for the interaction review for that assignment. Score cap is the maximum sum of review points that one should get in order to get the full extra credit.
Set a score cap and extra credit percentage for the interaction review for that assignment:
Reporting an interaction
As a student, one will then report an interaction that he or she had with his/her colleague. For that the student will navigate to a certain assignment.
You will then be presented with the following screen where you have to select that did you help someone or were you helped by someone?
Then you can submit your review response.
Once the interaction review is done, its status has to be confirmed.
Confirming the status
Once you have entered an interaction for helping someone, the helpee should then confirm whether the interaction is valid and then give a score to the helper.
Approving the interaction review
Once the interaction review has been done by the helper and the helpee, the instructor can then view this interaction and approve it.
Scores
Once the instructor has approved an interaction, the student can see the scores for that interaction in his/her score report for that assignment.
Code climate report
Code snippet from earlier project showing issues
As you can see in the code below, this is the code for a single method create for creating interaction review. This is just to give an example of why we need to refactor most of the code written for the interaction review feature. Its a very complex method and has code smells and lacks use of design patterns.
def create ################################################### #Add the values to the Scores, Response and ResponseMap tables. puts "Entered create" @assignment = Assignment.find(params[:assign]) if(params[:type] == "helpee") #Response created by the helpee. So both reviewer and reviewee are users helperid = User.find_by_name(params[:helper]).id @reviewerid = Participant.first(:conditions => ['parent_id = ? and user_id = ?',params[:assign],helperid]).id @revieweeid = Team.find(Participant.find(session[:participant_id]).team.id).id elsif(params[:type] == "helper") #Response created by helper. So the reviewee is a team @reviewerid = session[:participant_id] @revieweeid=Team.first(:conditions => ['parent_id=? and name=?',params[:assign],params[:teams]]).id end puts "The id of assignment" puts @assignment.id puts "The id of reviewer" puts @reviewerid puts "The id of reviewee" puts @revieweeid puts "Creating map now" map = InteractionResponseMap.create(:reviewed_object_id=>@assignment.id,:reviewer_id=>@reviewerid,:reviewee_id=>@revieweeid) @response = Response.create(:map_id=>map.id,:additional_comment=>params[:review][:comments]) puts "Created database entries for map and response" @questionnaire = Questionnaire.find(params[:questionnaire_id]) puts "Identified the questionnaire" questions = @questionnaire.questions params[:responses].each_pair do |k,v| score = Score.create(:response_id => @response.id, :question_id => questions[k.to_i].id, :score => v[:score], :comments => v[:comment]) if(questions[k.to_i].txt == "Score") puts "Score question. Score is " puts v[:score] @actualscore = v[:score] end end puts "Created database entries for scores" ################################################### #Older implementation starts here. Certain parts of it are redundant and need to be removed @curr_participant = session[:participant_id] # for helpee entries into the table if(params[:type]=="helpee") #@user = User.find_by_name(params[:helper]) #Find the user by his login instead of his name @user = User.find_by_name(params[:helper]) p params[:helper] # if username wrong then error displayed and redirected to a new form again if !@user if params[:helper].to_s == "" @error = "Username cannot be blank." else @error = "User \"" + params[:helper].to_s + "\" does not exist." end @user_name = params[:helper].to_s @user_name = @user.name.to_s @assignment = params[:assign] @type = params[:type] @id = session[:participant_id] @participant_id = session[:participant_id] @my_team_id = Participant.find(@participant_id).team.id @my_team = Team.find(@my_team_id) @interaction = HelpeeInteraction.new(params[:interactions]) @advices = InteractionAdvice.find_all_by_assignment_id(params[:assignment_id]) @advices = @advices.sort{|x,y|x.score<=>y.score} flash[:alert] = @error render :action => 'new' , :assignment_id=>params[:assign], :type=>params[:type], :id=>session[:participant_id], :interaction => @interaction else @helper_user = @user.id @helper_assignment= params[:assign] @helper_participant=Participant.first(:conditions => ['parent_id = ? and user_id = ?',params[:assign],@helper_user]) @selected_team=Team.find(Participant.find(session[:participant_id]).team.id) @helpee_record = HelpeeInteraction.first(:conditions => ["participant_id = ? AND team_id = ?", @helper_participant, @selected_team.id]) if !TeamsUser.first(:conditions => ['team_id = ? and user_id = ?', @selected_team.id, @helper_user]) # check if current helpee interaction already exists if !@helpee_record @interaction = HelpeeInteraction.new(params[:interactions]) @interaction.interaction_datetime = params[:interaction_date] @interaction.team_id = @selected_team.id #@interaction.score = params[:score] @interaction.score = @actualscore @interaction.participant_id=@helper_participant.id @interaction.status='Not Confirmed' # on save check if helper has already filled the form.If yes then set status of helper and helpee to 'Confirmed' if @interaction.save @helper_record = HelperInteraction.first(:conditions => ["participant_id = ? AND team_id = ?", @interaction.participant_id,@interaction.team_id ]) if @helper_record @helpee_record=HelpeeInteraction.first(:conditions => ["participant_id = ? AND team_id = ?", @interaction.participant_id,@interaction.team_id ]) @helpee_record.update_attribute('status','Confirmed') @helper_record.update_attribute('status','Confirmed') end flash[:note] =" Interaction created successfully." redirect_to :controller=>'interaction', :action=>'view',:assignment=>params[:assign], :id=>session[:participant_id] else @error = "" @assignment = params[:assign] @user_name = params[:helper].to_s @type = params[:type] @id = session[:participant_id] @participant_id = session[:participant_id] @my_team_id = Participant.find(@participant_id).team.id @my_team = Team.find(@my_team_id) @advices = InteractionAdvice.find_all_by_assignment_id(params[:assignment_id]) @advices = @advices.sort{|x,y|x.score<=>y.score} @interaction.errors.each { |err| @error += err[1] + "</br>"} flash[:alert] = @error render :action => 'new' , :assignment_id=>params[:assign], :type=>params[:type], :id=>session[:participant_id], :interaction => @interaction end else flash[:alert] = "Interaction already reported." redirect_to :controller=>'interaction', :action=>'view', :id=>session[:participant_id] end else @user_name = params[:helper].to_s @assignment = params[:assign] @type = params[:type] @id = session[:participant_id] @participant_id = session[:participant_id] @my_team_id = Participant.find(@participant_id).team.id @my_team = Team.find(@my_team_id) @interaction = HelpeeInteraction.new(params[:interactions]) @advices = InteractionAdvice.find_all_by_assignment_id(params[:assignment_id]) @advices = @advices.sort{|x,y|x.score<=>y.score} flash[:alert] = "Dont act smart. User cant belong to the same team!" render :action => 'new' , :assignment_id=>params[:assign], :type=>params[:type], :id=>session[:participant_id], :interaction => @interaction end end #for helper entries into the table elsif (params[:type]=="helper") @selected_team=Team.first(:conditions => ['parent_id=? and name=?',params[:assign],params[:teams]]) helper_record1 = HelperInteraction.first(:conditions => ["participant_id = ? AND team_id = ?",session[:participant_id],@selected_team.id ]) # check if current helper interaction already exists if @helper_record1 flash[:alert] ="Interaction already reported.." redirect_to :action => 'new' , :assignment_id=>params[:assign], :type=>params[:type], :id=>session[:participant_id] else @interaction = HelperInteraction.new(params[:interactions]) @interaction.participant_id=session[:participant_id] @interaction.interaction_datetime=params[:interaction_date] @interaction.team_id=@selected_team.id @interaction.status='Not Confirmed' if @interaction.save @helpee_record2 = HelpeeInteraction.first(:conditions => ["participant_id = ? AND team_id = ?", @interaction.participant_id, @interaction.team_id ]) if @helpee_record2 @helpee_record2.update_attribute('status','Confirmed') @helper_record2=HelperInteraction.first(:conditions => ["participant_id = ? AND team_id = ?", @interaction.participant_id, @interaction.team_id ]) @helper_record2.update_attribute('status','Confirmed') end flash[:note] =" Interaction created successfully." redirect_to :controller=>'interaction', :action=>'view',:assignment=>params[:assign], :id=>session[:participant_id] # display errors else @error = "" @assignment = params[:assign] @type = params[:type] @id = session[:participant_id] @participant_id = session[:participant_id] @interaction.errors.each { |err| @error += err[1] + "</br>"} flash[:alert] = @error render :action => 'new' , :assignment_id=>params[:assign], :type=>params[:type], :id=>session[:participant_id], :interaction => @interaction end end end end
Repository for reference
You can use the repository (https://github.com/aswin89thee/expertiza.git) as a reference. Use the E722 branch under this repository. (https://github.com/aswin89thee/expertiza/tree/E722) but be careful that
- 161 files are changed in the commit made to introduce the feature of interaction review
- merging the changes is a huge challenge and time-consuming work
- the code written has many flaws and needs a lot of refactoring
- the views are broken
- code in this repository is not fully functional
- lots of views have been changed in the latest expertiza which are not present in this repository
- none of the db changes mentioned below are there in the repository
- none of the migrations mentioned below are present in the repository
- none of the the database tables mentioned below is populated with the pre-required configuration values for Interaction Review in the test database.
Steps for re-building E722
- Refer to the repository mentioned above.
- Clone this repository.
- Add the development repository of expertiza as upstream. To do this, refer to the steps, mentioned here.
- After the merge is complete, refactor all of the following classes:
- app/controllers/interaction_controller.rb
- app/models/helpee_interaction.rb
- app/models/helper_interaction.rb
- app/models/interaction_advice.rb
- app/models/interaction_response_map.rb
- app/models/interaction_review_questionnaire.rb
- app/models/interaction_weight.rb
- Add the following migrations
- db/migrate/create_questionnaire_folder_nodes.rb
# Add code in self.up Node.find(:all, :conditions => ['type in ("QuestionnaireTypeNode","QuestionnaireNode")']).each{ | node | node.destroy } parent = TreeFolder.find_by_name("Questionnaires") pNode = FolderNode.find_by_node_object_id(parent.id) fnode = TreeFolder.create(:name => 'Interaction Review', :child_type => 'QuestionnaireNode') pfNode = FolderNode.create(:parent_id => pNode.id, :node_object_id => fnode.id) InteractionReviewQuestionnaire.find(:all).each{ | questionnaire | QuestionnaireNode.create(:parent_id => pfNode.id, :node_object_id => questionnaire.id) }
- db/migrate/update_questionnaire_menus.rb
# Add code in self.up interaction_review_rubrics_action = ControllerAction.find_or_create_by_name('goto_interactionreview_rubrics') interaction_review_rubrics_action.site_controller_id = site_controller.id interaction_review_rubrics_action.save MenuItem.create(:name => 'manage/questionnaires/interaction review rubrics', :label => 'Interaction review rubrics', :parent_id => item.id, :seq => 8, :controller_action_id => interaction_review_rubrics_action.id)
- For current expertiza, many of the views have been changed. Following are some of the views you need to change.
- app/controllers/tree_display_controller.rb
def goto_interactionreview_rubrics node_object = TreeFolder.find_by_name('Interaction Review') session[:root] = FolderNode.find_by_node_object_id(node_object.id).id redirect_to :controller => 'tree_display', :action => 'list' end
- app/views/assignments/edit/_rubrics.html.erb
# Add code in jQuery(document).ready(function () {} addQuestionnaireTableRow( 'InteractionReviewQuestionnaire', <%= questionnaire(@assignment, 'InteractionReviewQuestionnaire').to_json.html_safe %>.interaction_review_questionnaire, <%= assignment_questionnaire(@assignment, 'InteractionReviewQuestionnaire').to_json.html_safe %>.assignment_questionnaire, <%= questionnaire_options(@assignment, 'InteractionReviewQuestionnaire').to_json.html_safe %> );
- Changes to be made to database tables related to interaction review feature
- menu_items - Add interaction review rubrics with the name /manage/questionnaires/goto interactionreview rubrics
- nodes - Insert the QuestionnateNode and FolderNode for Treefolder "Interaction review"
- tree_folders - Insert a row for Interaction Review with the child_type as QuestionnaireNode
- controller_actions - Mention the action goto_interactionreview_rubrics in it
- interactions - Stores the interactions saved
- interaction_weights - Stores the weight associated with each interaction review