CSC/ECE 517 Fall 2015/oss E1570 avr: Difference between revisions

From Expertiza_Wiki
Jump to navigation Jump to search
No edit summary
 
(58 intermediate revisions by 3 users not shown)
Line 13: Line 13:
   
   


'''What they do:'''
'''Controller Responsibilities:'''
This controller deals with displaying “trees” of objects to the instructor.  When an instructor logs in, (s)he is greeted with a homepage that lists questionnaires (rubrics, quizzes, surveys), courses, and assignments.  These objects are displayed in a “tree,” allowing the user to click on the top-level object and see the objects beneath it.
This controller deals with displaying “trees” of objects to the instructor.  When an instructor logs in, (s)he is greeted with a homepage that lists questionnaires (rubrics, quizzes, surveys), courses, and assignments.  These objects are displayed in a “tree,” allowing the user to click on the top-level object and see the objects beneath it.


'''What's wrong with it:'''
'''Bad practices followed:'''
* Many Duplicate Methods.
* Many Duplicate Methods.
* Very Long Methods combining many Functionalities.
* Very Long Methods combining many Functionalities.
* Redundant methods not being used anywhere.
* Redundant methods not being used anywhere.


'''What needs to be done:'''
'''Refactoring to be done:'''
#  Split  <font face=Courier New>get_children_node_ng </font> and <font face=Courier New>get_children_node_2_ng </font> into smaller methods and give reasonable names to them and make sure implement common code in a single method.
#  Split  <font face=Courier New>get_children_node_ng </font> and <font face=Courier New>get_children_node_2_ng </font> into smaller methods and give reasonable names to them and make sure implement common code in a single method.
#  Merge  all the repeating methods into a single method.
#  Write functional tests for the TreeDispayController.
#  Remove commented code in list method.


=Changes Made=


=Changes Made=
We used the DRY principle while refactoring our code to remove duplicates in get_children_node_ng and get_children_node_2_ng methods.


==TreeDisplayController==
==TreeDisplayController==
Line 36: Line 40:
|- style="vertical-align:top;"
|- style="vertical-align:top;"
|-------
|-------
| Put ur txt here
| goto_questionnaires, goto_review_rubrics, goto_metareview_rubrics, goto_teammatereview_rubrics, goto_author_feedbacks, goto_global_survey, goto_surveys, goto_course_evaluations, goto_courses, goto_assignments
| put ur text here
| All these methods were merged into a single method with name go_to_menu_items which receives a parameter of the name of tree_folder object, such as "Questionnaires".
|Since all the methods were performing the same action, i.e passing the node object id to list method in TreeDisplayController, the name is passed a parameter to the go_to_menu_items method from "link" method in MenuItemsController. Using this parameter the respective object and its ID are found and is redirected to "list" method.
|-
|-
| get_children_node_ng
| get_children_node_ng
| rowspan="2" | Moved part of the code from these methods to newly created methods populate_rows,display_row,page_render methods.
| rowspan="2" | Moved part of the code from these methods to newly created methods: populate_rows,populate_1_row,page_render methods.
| rowspan="2" | These Methods had many functionalities being implemented which made the method look lengthy and moreover these methods were performing almost similar functions which could be grouped together and reduce the overall code length.
| rowspan="2" | These Methods had many functionalities being implemented which made the method look lengthy and moreover these methods were performing almost similar functions which could be grouped together and reduce the overall code length.
|-
|-
| get_children_node_2_ng
| get_children_node_2_ng
|}
==MenuItemsController==
{| class="wikitable"
|-
|-
| -------
! style="width:13%;"|Method Name
| Put ur txt here
! style="width:33%;"|Changes Made
| put ur text here
! style="width:43%;"|Reason For Change
|- style="vertical-align:top;"
|-------
| link
| Redirect url only for the menu_items altered in TreeDisplayController is changed to go_to_menu_items_url.
| Since the 10 methods had been merged into one method in TreeDisplayController, the redirect url is set to go_to_menu_items url.
|-
|-
|}
|}
=='''How to test the changes from UI'''==
<!--{| class="wikitable"
|-
|-->
* Login in as an instructor or admin using credentials (admin with password: admin or instructor6 with password: password)
* To check the changes made in go_to_menu_items method, hover over the Manage tab in the navigation bar on the top  and click all the links and check whether they are being redirected to correct pages. For example, if Questionnaires is clicked, you should be | redirected directly to the page displaying all the questionnaires with its sub-categories like Reviews, Surveys etc.
* To test the changes made in get_children_node_ng and get_children_node_2_ng methods, click on the sub categories under each of the parent tree displays (Courses, Assignments and Questionnaires) and all of them will further expand to show the details. (Click on the name of the Course/Asignment/Questionnaire to expand them)
<!--|-
|}-->
=Direct access to sub categories in tree display=
[[File:Manage menu traversal.jpg |center]]
=Checking the direct access tabs from navigation bar=
[[File:Rsz questionnaires.jpg |center]]
=Checking the sub categories in each parent Tree=
[[File:Rsz sub tree traversal.jpg |center]]


= Re-factored Code =
= Re-factored Code =
Line 132: Line 170:
</pre>
</pre>
|<pre>
|<pre>
def get_children_node_ng
  def get_children_node_ng
    # First Level Of Tree Display with Folder Nodes(Courses, Assisgnments,Questionnaires )
     childNodes = {}
     childNodes = {}
     if params[:reactParams][:child_nodes].is_a? String
     if params[:reactParams][:child_nodes].is_a? String
Line 140: Line 177:
       childNodes = params[:reactParams][:child_nodes]
       childNodes = params[:reactParams][:child_nodes]
     end
     end
     tmpRes = {}
     ch_nodes = {}
    res = {}
     for node in childNodes
     for node in childNodes
       # Declaring Foldernode Object as New
       # Declaring Foldernode Object as New
Line 150: Line 186:
       # fnode is the parent node
       # fnode is the parent node
       # ch_nodes are childrens
       # ch_nodes are childrens
       ch_nodes = fnode.get_children(nil, nil, session[:user].id, nil, nil)
       ch_nodes[fnode.get_name] = fnode.get_children(nil, nil, session[:user].id, nil, nil)
       tmpRes[fnode.get_name] = ch_nodes
       # cnode = fnode.get_children("created_at", "desc", 2, nil, nil)
 
     end
     end
       call_function ="get_children_node_ng"
       call_function ="get_children_node_ng"
       # Row Populating
       #Render JSON of the child nodes
       populate_rows(tmpRes,call_function)
       populate_rows(ch_nodes,call_function)
   end
   end
</pre>
</pre>
|}
|}


==Removing duplicate methods==
==Refactoring get_children_node_2_ng method==
The ResponseController allows the user to create and edit responses to questionnaires, and the functionality changed over time, causing two new_feedback and view methods to be created; the oldest of which doesn't get called anymore.
 


{| class="wikitable"
{| class="wikitable"
Line 168: Line 203:
! |Before Changes
! |Before Changes
! |After Changes  
! |After Changes  
|- style="vertical-align:bottom;"
|- style="vertical-align:top;"
|<pre>
|<pre>
def new_feedback
  def get_children_node_2_ng
     review = Response.find(params[:id])
     childNodes = {}
    if review
    if params[:reactParams2][:child_nodes].is_a? String
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first
       childNodes = JSON.parse(params[:reactParams2][:child_nodes])
       map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id: reviewer.id).first
      if map.nil?
        map = FeedbackResponseMap.create(:reviewed_object_id => review.id, :reviewer_id => reviewer.id,
                                        :reviewee_id => review.map.reviewer.id)
      end
      redirect_to :action => 'new', :id => map.map_id, :return => "feedback"
     else
     else
       redirect_to :back
       childNodes = params[:reactParams2][:child_nodes]
     end
     end
  end
    tmpRes = {}
    res = []
    fnode = eval(params[:reactParams2][:nodeType]).new
    childNodes.each do |key, value|
      fnode[key] = value
    end
 
    ch_nodes = fnode.get_children(nil, nil, session[:user].id, nil, nil)
    tmpRes = ch_nodes
    if tmpRes
      for child in tmpRes
        nodeType = child.type
        res2 = {}
        res2["nodeinfo"] = child
        res2["name"] = child.get_name
        res2["key"] = params[:reactParams2][:key]
        res2["type"] = nodeType
 
        res2["private"] = child.get_private
        res2["creation_date"] = child.get_creation_date
        res2["updated_date"] = child.get_modified_date
        if nodeType == 'CourseNode' || nodeType == "AssignmentNode"
          res2["directory"] = child.get_directory
          instructor_id = child.get_instructor_id
          res2["instructor_id"] = instructor_id
          unless (instructor_id.nil?)
            res2["instructor"] = User.find(instructor_id).name
          else
            res2["instructor"] = nil
          end


def new_feedback
          res2["is_available"] = is_available(session[:user], instructor_id) || (session[:user].role_id == 6 &&
    review = Response.find(params[:id])
Ta.get_my_instructors(session[:user].id).include?(instructor_id) && ta_for_current_course?(child))
    if review
          if nodeType == "AssignmentNode"
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first
            res2["course_id"] = child.get_course_id
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first
            res2["max_team_size"] = child.get_max_team_size
      if map.nil?
            res2["is_intelligent"] = child.get_is_intelligent
        #if no feedback exists by dat user den only create for dat particular response/review
            res2["require_quiz"] = child.get_require_quiz
        map = FeedbackResponseMap.create(:reviewed_object_id => review.id, :reviewer_id => reviewer.id,
            res2["allow_suggestions"] = child.get_allow_suggestions
                                        :reviewee_id => review.map.reviewer.id)
            res2["has_topic"] = SignUpTopic.where(['assignment_id = ?', child.node_object_id]).first ? true : false
          end
        end
        res << res2
       end
       end
      redirect_to :action => 'new', :id => map.id, :return => "feedback"
    end
     else
 
       redirect_to :back
     respond_to do |format|
       format.html {render json: res}
     end
     end
   end
   end
</pre>
</pre>
|<pre>
|<pre>
def new_feedback
def get_children_node_2_ng
     review = Response.find(params[:id])
     # Second Level of Tree Display with Children Nodes
    if review
    childNodes = {}
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first
    if params[:reactParams2][:child_nodes].is_a? String
       map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id: reviewer.id).first
       childNodes = JSON.parse(params[:reactParams2][:child_nodes])
      if map.nil?
        #if no feedback exists by dat user den only create for dat particular response/review
        map = FeedbackResponseMap.create(:reviewed_object_id => review.id, :reviewer_id => reviewer.id,
                                        :reviewee_id => review.map.reviewer.id)
      end
      redirect_to :action => 'new', :id => map.id, :return => "feedback"
     else
     else
       redirect_to :back
       childNodes = params[:reactParams2][:child_nodes]
     end
     end
  end
 
</pre>
    res = []
|- style="vertical-align:bottom;"
     fnode = eval(params[:reactParams2][:nodeType]).new
|<pre>
     childNodes.each do |key, value|
def view
       fnode[key] = value
     @response = Response.find(params[:id])
    return if redirect_when_disallowed(@response)
    @map = @response.map
    get_content
    @review_scores = Array.new
     @question_type = Array.new
    @questions.each do |question|
       @review_scores << Score.where(response_id: @map.response_id, question_id:  question.id).first
      @question_type << QuestionType.find_by_question_id(question.id)
     end
     end
  end


def view
     ch_nodes = fnode.get_children(nil, nil, session[:user].id, nil, nil)
     @response = Response.find(params[:id])
 
    return if action_allowed?(@response)
     call_function = "get_children_node_2_ng"
    @map = @response.map
     populate_rows(ch_nodes, call_function)
    get_content
    get_scores(@response, @questions)
  end
</pre>
|<pre>
def view
     @response = Response.find(params[:id])
    return if action_allowed?(@response)
    @map = @response.map
    get_content
     get_scores(@response, @questions)
   end
   end
</pre>
</pre>
|}
|}


==Moving code to the proper place==
==Common Methods Added to get_children_node_ng and get_children_node_2_ng controllers ==
The ResponseController allows the user to create and edit responses to questionnaires, in doing so, there needs to be some sort of authentication, and the proper place for that is in the action_allowed? method, however the un-refactored code did in the redirect_when_disallowed method. Moreover, once this code was moved to the action_allowed? method, all of the references to redirect_when_disallowed were removed (action_allowed? gets called automatically).
 
===populate_rows ===
 
This is a new Common Method for both get_children_node_ng and get_children_node_2_ng  that does the functionality of rendering a page with data from all nodes by calling another method populate_1_row(). There is another Method call that happens in this method which as a whole renders the List View.
 
<!--{| class="wikitable"


{| class="wikitable"
! |populate_rows()
|-
! |Before Changes
! |After Changes
|- style="vertical-align:top;"
|- style="vertical-align:top;"
|<pre>
|--><pre>
def action_allowed?
  def populate_rows(list,call_function) #render page with data for all nodes in list
     current_user
     if call_function == "get_children_node_ng"
  end
      tmpRes ={}
      tmpRes = list
      res = {}
      for nodeType in tmpRes.keys
        # declaring a new array
        res[nodeType] = Array.new
        for node in tmpRes[nodeType]
          res[nodeType] << populate_1_row(node)
        end
      end


def redirect_when_disallowed(response)
    else
    # For author feedback, participants need to be able to read feedback submitted by other teammates.
      tmpRes = list
    # If response is anything but author feedback, only the person who wrote feedback should be able to see it.
      res = []
    if response.map.read_attribute(:type) == 'FeedbackResponseMap' && response.map.assignment.team_assignment?
      if tmpRes
      team = response.map.reviewer.team
        for child in tmpRes
      unless team.has_user session[:user]
          res_node = {}
        redirect_to '/denied?reason=You are not on the team that wrote this feedback'
          res_node = populate_1_row(child)
      else
          res_node["key"] = params[:reactParams2][:key]
         return false
          res << res_node
         end
       end
       end
      response.map.read_attribute(:type)
     end
     end
     !current_user_id?(response.map.reviewer.user_id)
     page_render(res)
   end
   end
</pre>
</pre>
|<pre>
<!-- } -->
   def action_allowed?
 
     # For author feedback, participants need to be able to read feedback submitted by other teammates.
===populate_1_row ===
     # If response is anything but author feedback, only the person who wrote feedback should be able to see it.
 
     if Response.where(id: params[:id]).empty?
'This is a new Method that is called from Method populate_row() and fetches all the child node names from respective Controller actions and then populates the tmpObject.
      true
 
     elsif
<!--{| class="wikitable"
    response = Response.find(params[:id])
|-
     if response.map.read_attribute(:type) == 'FeedbackResponseMap' && response.map.assignment.team_assignment?
! |populate_1_row()
       team = response.map.reviewer.team
|- style="vertical-align:top;"
       unless team.has_user session[:user]
|--><pre>
        redirect_to '/denied?reason=You are not on the team that wrote this feedback'
   def populate_1_row(node) #return JSON for 1 Node
    tmpObject = {}
     tmpObject["nodeinfo"] = node
     # all the child nodes names got and put in tmpObject from respective controller actions
     tmpObject["name"] = node.get_name
     tmpObject["type"] = node.type
     if node.type == 'CourseNode' || node.type == "AssignmentNode"
      tmpObject["directory"] = node.get_directory
      tmpObject["creation_date"] = node.get_creation_date
       tmpObject["updated_date"] = node.get_modified_date
      tmpObject["private"] = node.get_private
      instructor_id = node.get_instructor_id
      tmpObject["instructor_id"] = instructor_id
       unless (instructor_id.nil?)
        tmpObject["instructor"] = User.find(instructor_id).name
       else
       else
         return false
         tmpObject["instructor"] = nil
      end
 
      tmpObject["is_available"] = is_available(session[:user], instructor_id) || (session[:user].role_id == 6 && Ta.get_my_instructors(session[:user].id).include?(instructor_id) && ta_for_current_course?(node))
      if node.type == "AssignmentNode"
        tmpObject["course_id"] = node.get_course_id
        tmpObject["max_team_size"] = node.get_max_team_size
        tmpObject["is_intelligent"] = node.get_is_intelligent
        tmpObject["require_quiz"] = node.get_require_quiz
        tmpObject["allow_suggestions"] = node.get_allow_suggestions
        tmpObject["has_topic"] = SignUpTopic.where(['assignment_id = ?', node.node_object_id]).first ? true : false
       end
       end
      response.map.read_attribute(:type)
    end
    current_user_id?(response.map.reviewer.user_id)
     end
     end
    tmpObject
   end
   end
</pre>
</pre>
|}
<!--}-->
 
===page_render ===


==Moving get_scores to the Response Model==
This is also a common Method which integrates the rendering functionality of get_children_node_ng and get_children_node_2_ng making sure both levels are properly populated in the view.'
The get_scores method was being implemented in the controller. Its function fits better in the model.
As such, the method was moved and changed to retain the functionality of code that uses it. Since the variables it requires were no longer in scope, they're passed in as arguments. Also due to scope, the result has to be explicitly returned.


{| class="wikitable"
<!--{| class="wikitable"
|-
|-
! |Before Changes
! |page_render()
! |After Changes
|- style="vertical-align:top;"
|- style="vertical-align:top;"
|<pre>
|--><pre>
In response_controller.rb
  def page_render(list) # Common Render Functionality for get_children_node_ng and get_children_node_2_ng methods
 
     respond_to do |format|
def get_scores
       format.html {render json: list}
    @review_scores = []
    @question_type = []
     @questions.each do |question|
       @review_scores << Score
        .where(
          response_id: @response.id,
          question_id:  question.id
        ).first
      @question_type << QuestionType.find_by_question_id(question.id)
     end
     end
   end
   end
</pre>
</pre>
|<pre>
<!--}-->
In response.rb


def get_scores(response, questions)
== Method Removal==
    review_scores = []
There was a Method which dint have any Routes defined in the Routes.rb file and was not called in any of the Controller . After Careful analysis we descided to remove the method from the tree Display Controller.
    question_type = []
    questions.each do |question|
      review_scores << Score
                            .where(
                                response_id: response.id,
                                question_id:  question.id
                            ).first
      question_type << QuestionType.find_by_question_id(question.id)
    end
      question_type
  end


</pre>
=== filter ===
<pre>
In response_controller.rb


def view
<!--{| class="wikitable"
    @response = Response.find(params[:id])
    @map = @response.map
    get_content
    @question_type = @response.get_scores(@response, @questions)
  end
</pre>
|}
 
==Moving the sorting of response versions logic out of rereview method==
The code to sort response versions has been moved from rereview method to a separate method. This was done because the rereview method was becoming very long and confusing.
 
{| class="wikitable"
|-
|-
! |Before Changes
! |filter
! |After Changes
|- style="vertical-align:top;"
|- style="vertical-align:top;"
|<pre>
|--><pre>
In method rereview
  def filter
 
     search = params[:filter_string]
      def rereview
     filter_node = params[:filternode]
     @map=ResponseMap.find(params[:id])
     qid = 'filter+'
     get_content
    array_not_empty=0
     @review_scores=Array.new
    @prev=Response.all
    #get all versions and find the latest version
    for element in @prev
      if (element.map.id==@map.map.id)
        array_not_empty=1
        @review_scores << element
      end
    end


    latestResponseVersion
     if filter_node == 'QAN'
    #sort all the available versions in descending order.
       assignment = Assignment.find_by_name(search)
     if @prev.present?
       if assignment
       @sorted=@review_scores.sort { |m1, m2| (m1.version_num and m2.version_num) ? m2.version_num <=> m1.version_num : (m1.version_num ? -1 : 1) }
        assignment_questionnaires = AssignmentQuestionnaire.where(assignment_id: assignment.id)
       @largest_version_num=@sorted[0]
        if assignment_questionnaires
      @latest_phase=@largest_version_num.created_at
          assignment_questionnaires.each { |q| qid << "#{q.questionnaire_id.to_s}+" }
      due_dates = DueDate.where(["assignment_id = ?", @assignment.id])
          session[:root] = 1
      @sorted_deadlines=Array.new
      @sorted_deadlines=due_dates.sort { |m1, m2| (m1.due_at and m2.due_at) ? m1.due_at <=> m2.due_at : (m1.due_at ? -1 : 1) }
      current_time=Time.new.getutc
      #get the highest version numbered review
      next_due_date=@sorted_deadlines[0]
      #check in which phase the latest review was done.
      for deadline_version in @sorted_deadlines
        if (@largest_version_num.created_at < deadline_version.due_at)
          break
         end
         end
       end
       end
</pre>
     elsif filter_node == 'ACN'
|<pre>
       session[:root] = 2
In method rereview
       qid << search
 
  def rereview
     @map=ResponseMap.find(params[:id])
 
    # store response content in map
    get_content
 
    previous_responses
    #sort all the available versions in descending order.
    if @prev.present?
       sortResponseVersion
    end
</pre>
<pre>
def sortResponseVersion
    @sorted=@review_scores.sort { |m1, m2| (m1.version_num and m2.version_num) ? m2.version_num <=> m1.version_num : (m1.version_num ? -1 : 1) }
    @largest_version_num=@sorted[0]
    @latest_phase=@largest_version_num.created_at
    due_dates = DueDate.where(["assignment_id = ?", @assignment.id])
    @sorted_deadlines=Array.new
    @sorted_deadlines=due_dates.sort { |m1, m2| (m1.due_at and m2.due_at) ? m1.due_at <=> m2.due_at : (m1.due_at ? -1 : 1) }
    current_time=Time.new.getutc
    #get the highest version numbered review
    next_due_date=@sorted_deadlines[0]
    #check in which phase the latest review was done.
    for deadline_version in @sorted_deadlines
       if (@largest_version_num.created_at < deadline_version.due_at)
        break
      end
    end
    for deadline_time in @sorted_deadlines
      if (current_time < deadline_time.due_at)
        break
      end
     end
     end
    return qid
   end
   end
</pre>
</pre>
|}
<!--}-->


==Removing special code in rereview method==
==Removing duplicate methods==
The rereview method had some special code to check if the current user is jace_smith and uses a custom hard-coded rubric instead of a rubric from the system. This was a code segment that was written when multipart rubrics were first tested. Removing this code will break the assignment and so the code was moved to a separate method and commented as a kludge.


{| class="wikitable"
{| class="wikitable"
Line 452: Line 429:
|- style="vertical-align:top;"
|- style="vertical-align:top;"
|<pre>
|<pre>
In method rereview
# direct access to questionnaires
  def goto_questionnaires
    node_object = TreeFolder.find_by_name('Questionnaires')
    session[:root] = FolderNode.find_by_node_object_id(node_object.id).id
    redirect_to :controller => 'tree_display', :action => 'list'
  end


      #**********************
  # direct access to review rubrics
      # Check whether this is Jen's assgt. & if so, use her rubric
  def goto_review_rubrics
      if (@assignment.instructor_id == User.find_by_name("jace_smith").id) && @title == "Review"
    node_object = TreeFolder.find_by_name('Review')
        if @assignment.id < 469
     session[:root] = FolderNode.find_by_node_object_id(node_object.id).id
          @next_action = "update"
    redirect_to :controller => 'tree_display', :action => 'list'
          render :action => 'custom_response'
        else
          @next_action = "update"
          render :action => 'custom_response_2011'
        end
      else
        # end of special code (except for the end below, to match the if above)
        #**********************
        render :action => 'response'
      end
     else
      #else create a new version and update it.
      @header = "New"
      @next_action = "create"
      @feedback = params[:feedback]
      @map = ResponseMap.find(params[:id])
      @return = params[:return]
      @modified_object = @map.map_id
      get_content
      #**********************
      # Check whether this is Jen's assgt. & if so, use her rubric
      if (@assignment.instructor_id == User.find_by_name("jace_smith").id) && @title == "Review"
        if @assignment.id < 469
          @next_action = "create"
          render :action => 'custom_response'
        else
          @next_action = "create"
          render :action => 'custom_response_2011'
        end
      else
        # end of special code (except for the end below, to match the if above)
        #**********************
        render :action => 'response'
      end
    end
   end
   end
</pre>
|<pre>
In method rereview


   # Check whether this is Jen's assgt. & if so, use her rubric
   # direct access to metareview rubrics
      if (@assignment.instructor_id == User.find_by_name("jace_smith").id) && @title == "Review"
  def goto_metareview_rubrics
        handle_jens_assignment
    node_object = TreeFolder.find_by_name('Metareview')
      else
     session[:root] = FolderNode.find_by_node_object_id(node_object.id).id
        render :action => 'response'
    redirect_to :controller => 'tree_display', :action => 'list'
      end
     else
      #else create a new version and update it.
      @header = "New"
      @next_action = "create"
      @feedback = params[:feedback]
      @map = ResponseMap.find(params[:id])
      @return = params[:return]
      @modified_object = @map.map_id
      get_content
      # Check whether this is Jen's assgt. & if so, use her rubric
      if (@assignment.instructor_id == User.find_by_name("jace_smith").id) && @title == "Review"
        handle_jens_assignment
      else
        render :action => 'response'
      end
    end
   end
   end
</pre>
 
<pre>
  # direct access to teammate review rubrics
#kludge for checking if assignment is jen's assignment and using her rubric if it is
   def goto_teammatereview_rubrics
   def handle_jens_assignment
     node_object = TreeFolder.find_by_name('Teammate Review')
     if @assignment.id < 469
    session[:root] = FolderNode.find_by_node_object_id(node_object.id).id
      @next_action = "update"
    redirect_to :controller => 'tree_display', :action => 'list'
      render :action => 'custom_response'
    else
      @next_action = "update"
      render :action => 'custom_response_2011'
    end
   end
   end
</pre>
|}


=Steps to verify changes=
  # direct access to author feedbacks
  def goto_author_feedbacks
    node_object = TreeFolder.find_by_name('Author Feedback')
    session[:root] = FolderNode.find_by_node_object_id(node_object.id).id
    redirect_to :controller => 'tree_display', :action => 'list'
  end


==Action Allowed==
  # direct access to global survey
Action allowed is called before every method call to confirm whether or not the currently logged in user has the required privileges to complete the requested action.
  def goto_global_survey
To test the functionality of this method one has to attempt to complete an action that they have privileges to complete, and confirm that they're allowed to complete it. One also has to attempt to complete an action that they don't have the privileges to complete, and confirm that they're not allowed to complete it.
    node_object = TreeFolder.find_by_name('Global Survey')
    session[:root] = FolderNode.find_by_node_object_id(node_object.id).id
    redirect_to :controller => 'tree_display', :action => 'list'
  end


===Allowed===
  # direct access to surveys
Log into the application with the user having a student's role (<b>User Id:</b> user5072, <b>Password:</b> password)
  def goto_surveys
    node_object = TreeFolder.find_by_name('Survey')
    session[:root] = FolderNode.find_by_node_object_id(node_object.id).id
    redirect_to :controller => 'tree_display', :action => 'list'
  end


# Click on Assignments, and you should see the following:
  # direct access to course evaluations
  def goto_course_evaluations
    node_object = TreeFolder.find_by_name('Course Evaluation')
    session[:root] = FolderNode.find_by_node_object_id(node_object.id).id
    redirect_to :controller => 'tree_display', :action => 'list'
  end


[[File:actionallowedPass.png]]
  # direct access to courses
  def goto_courses
    node_object = TreeFolder.find_by_name('Courses')
    session[:root] = FolderNode.find_by_node_object_id(node_object.id).id
    redirect_to :controller => 'tree_display', :action => 'list'
  end


===Not Allowed===
  # direct access to assignments
Log into the application with the user having an instructor's role (<b>User Id:</b> user6, <b>Password:</b> password)
  def goto_assignments
    node_object = TreeFolder.find_by_name('Assignments')
    session[:root] = FolderNode.find_by_node_object_id(node_object.id).id
    redirect_to :controller => 'tree_display', :action => 'list'
  end
</pre>
|<pre>
# direct access
def go_to_menu_items
    name = params[:params1]
    if name
      if name == "Review rubrics"
          name = "Review"
        elsif name == "Teammate review rubrics"
          name = "Teammate Review"
        elsif name == "Metareview rubrics"
          name = "Metareview"
        elsif name == "Author feedbacks"
          name = "Author Feedback"
        elsif name == "Global surveys"
          name = "Global Survey"
        elsif name == "Course evaluations"
          name = "Course Evaluation"
        elsif name == "Surveys"
            name = "Survey"
      end
      node_object = TreeFolder.find_by_name(name)
              session[:root] = FolderNode.find_by_node_object_id(node_object.id).id
      if node_object.name == "Courses"
              session[:last_open_tab] = 1
      elsif node_object.name == "Assignments"
              session[:last_open_tab] = 2
      elsif (node_object.id ==1 ||node_object.id ==4 ||node_object.id ==5 ||
              node_object.id ==6 ||node_object.id ==7 ||node_object.id ==8 ||node_object.id ==9||
              node_object.id ==10) # if node_object_name is Questionnaires or its child_nodes
          session[:last_open_tab] = 3  # for Questionnaires and all its childnodes
      end
          redirect_to :controller => 'tree_display', :action => 'list'
    else        # if the passed params is null, redirect to root
          redirect_to "/"
    end
</pre>
|- style="vertical-align:top;"
|}


# Click on Assignments, and you should see the following:
==Rspec Test==


[[File:actionallowedFail.png]]
We have written Rspec tests for the tree_display_controller and have run the same with success.


== get_scores  ==
From the home directory of the application, run the test as "rspec spec/controllers/tree_display_controller_spec.rb"
Get scores is called anytime the scores for reviews are shown. Given that, the way to test its correct functionality is to navigate to a completed review and make sure the scores are shown and are correct.
<!--{| class="wikitable"
|-
! |page_render()
|- style="vertical-align:top;"
|--><pre>
require 'rails_helper'


Log into the application with the user having a student's role (<b>User Id:</b> user5072, <b>Password:</b> password)
describe TreeDisplayController do
# Click on Assignments
# Click on Writing assignment 1b, Spring 2013
# Click on Others' Work
# Click on Review done at --2013-03-01 23:57:55 UTC


Successful loading of this page confirms the get_scores method.
describe "#list" do
    it "should not redirect to student_task controller if current user is an instructor" do
      allow(session[:user]).to receive("student?").and_return(false)
      post "list"
      response.should_not redirect_to(list_student_task_index_path)
end
    it "should redirect to student_task controller if current user is a student" do
      allow(session[:user]).to receive("student?").and_return(true)
      post "list"
      response.should redirect_to(list_student_task_index_path)
    end
end
describe "#ta_for_current_mappings?" do
    it "should return true if current user is a TA for current course" do
        allow(session[:user]).to receive("ta?").and_return(true)
    end
end


== rereview  ==
describe "#populate_rows" do
Rereview manages the versioning of multiple reviews for the same assignment. To test the correct functionality of review, one should attempt to update a review (i.e. 'rereview').
    let(:dbl) { double }
  before { expect(dbl).to receive(:populate_rows).with(Hash, String)}
    it "passes when the arguments match" do
      dbl.populate_rows({},"")
    end
end


Log into the application with the user having a student's role (<b>User Id:</b> user5072, <b>Password:</b> password)
describe "#populate_1_row" do
# Click on Assignments
    let(:dbl) { double }
# Click on Writing assignment 1b, Spring 2013
  before { expect(dbl).to receive(:populate_1_row).with(Node) }
# Click on Others' Work
    it "passes when the arguments match" do
# Click on Update (beside Metaprogramming in dynamically typed languages)
        dbl.populate_1_row(Node.new)
    end
  end


Successful loading of this page confirms the rereview method.
  describe "#go_to_menu_items" do
    before do
          allow(nil).to receive(:find_by_node_object_id).and_return(nil)
          allow(nil).to receive(:id).and_return(nil)
          allow(nil).to receive(:name).and_return(true)
    end
      it "should receive Review Rubrics and redirect to list" do
          allow(nil).to receive(:find_by_name).with("Review").and_return(nil)
          get "go_to_menu_items", params1: "Review Rubrics"
          expect(response).to redirect_to(list_tree_display_index_path)
      end
      it "should receive Teammate review rubrics and redirect to list" do
          allow(nil).to receive(:find_by_name).with("Teammate review").and_return(nil)
          get "go_to_menu_items", params1: "Teammate review rubrics"
          expect(response).to redirect_to(list_tree_display_index_path)
      end
      it "should receive Metareview rubrics and redirect to list" do
          allow(nil).to receive(:find_by_name).with("Metareview").and_return(nil)
          get "go_to_menu_items", params1: "Metareview rubrics"
          expect(response).to redirect_to(list_tree_display_index_path)
      end
      it "should receive Author feedbacks and redirect to list" do
          allow(nil).to receive(:find_by_name).with("Author Feedback").and_return(nil)
          get "go_to_menu_items", params1: "Author feedbacks"
          expect(response).to redirect_to(list_tree_display_index_path)
      end
      it "should receive Global surveys and redirect to list" do
          allow(nil).to receive(:find_by_name).with("Global Survey").and_return(nil)
          get "go_to_menu_items", params1: "Global surveys"
          expect(response).to redirect_to(list_tree_display_index_path)
      end
      it "should receive Course evaluations and redirect to list" do
          allow(nil).to receive(:find_by_name).with("Course Evaluation").and_return(nil)
          get "go_to_menu_items", params1: "Course evaluations"
          expect(response).to redirect_to(list_tree_display_index_path)
      end
      it "should receive Surveys and redirect to list" do
          allow(nil).to receive(:find_by_name).with("Survey").and_return(nil)
          get "go_to_menu_items", params1: "Surveys"
          expect(response).to redirect_to(list_tree_display_index_path)
      end
      it "should redirect to root_url if request parameter is invalid" do
          allow(nil).to receive(:find_by_name).with(nil).and_return(nil)
          get "go_to_menu_items"
          expect(response).to redirect_to(root_path)
      end
    end
    describe "#drill" do
      it "redirect to list action" do
          get "drill" , root: 1
          session[:root].should == "1"
          expect(response).to redirect_to(list_tree_display_index_path)
      end
    end
end
</pre>
<!--}-->


=References=
=References=
<references></references>
<references></references>

Latest revision as of 21:59, 7 November 2015

E1570. Refactoring TreeDisplayController

This page provides a description of the Expertiza based OSS project. This project aimed at refactoring the TreeDisplayController.

Introduction to Expertiza

Expertiza is a web application where students can submit and peer-review learning objects (articles, code, web sites, etc). The Expertiza project is supported by the National Science Foundation.<ref>Expertiza</ref><ref>Wiki</ref>

Problem Statement

Classes involved:

tree_display_controller.rb

Controller Responsibilities: This controller deals with displaying “trees” of objects to the instructor. When an instructor logs in, (s)he is greeted with a homepage that lists questionnaires (rubrics, quizzes, surveys), courses, and assignments. These objects are displayed in a “tree,” allowing the user to click on the top-level object and see the objects beneath it.

Bad practices followed:

  • Many Duplicate Methods.
  • Very Long Methods combining many Functionalities.
  • Redundant methods not being used anywhere.

Refactoring to be done:

  1. Split get_children_node_ng and get_children_node_2_ng into smaller methods and give reasonable names to them and make sure implement common code in a single method.
  2. Merge all the repeating methods into a single method.
  3. Write functional tests for the TreeDispayController.
  4. Remove commented code in list method.

Changes Made

We used the DRY principle while refactoring our code to remove duplicates in get_children_node_ng and get_children_node_2_ng methods.

TreeDisplayController

Method Name Changes Made Reason For Change
goto_questionnaires, goto_review_rubrics, goto_metareview_rubrics, goto_teammatereview_rubrics, goto_author_feedbacks, goto_global_survey, goto_surveys, goto_course_evaluations, goto_courses, goto_assignments All these methods were merged into a single method with name go_to_menu_items which receives a parameter of the name of tree_folder object, such as "Questionnaires". Since all the methods were performing the same action, i.e passing the node object id to list method in TreeDisplayController, the name is passed a parameter to the go_to_menu_items method from "link" method in MenuItemsController. Using this parameter the respective object and its ID are found and is redirected to "list" method.
get_children_node_ng Moved part of the code from these methods to newly created methods: populate_rows,populate_1_row,page_render methods. These Methods had many functionalities being implemented which made the method look lengthy and moreover these methods were performing almost similar functions which could be grouped together and reduce the overall code length.
get_children_node_2_ng

MenuItemsController

Method Name Changes Made Reason For Change
link Redirect url only for the menu_items altered in TreeDisplayController is changed to go_to_menu_items_url. Since the 10 methods had been merged into one method in TreeDisplayController, the redirect url is set to go_to_menu_items url.


How to test the changes from UI

  • Login in as an instructor or admin using credentials (admin with password: admin or instructor6 with password: password)
  • To check the changes made in go_to_menu_items method, hover over the Manage tab in the navigation bar on the top and click all the links and check whether they are being redirected to correct pages. For example, if Questionnaires is clicked, you should be | redirected directly to the page displaying all the questionnaires with its sub-categories like Reviews, Surveys etc.
  • To test the changes made in get_children_node_ng and get_children_node_2_ng methods, click on the sub categories under each of the parent tree displays (Courses, Assignments and Questionnaires) and all of them will further expand to show the details. (Click on the name of the Course/Asignment/Questionnaire to expand them)


Direct access to sub categories in tree display

Checking the direct access tabs from navigation bar

Checking the sub categories in each parent Tree

Re-factored Code

Refactoring get_children_node_ng method

Before Changes After Changes
  def get_children_node_ng
    childNodes = {}
    if params[:reactParams][:child_nodes].is_a? String
      childNodes = JSON.parse(params[:reactParams][:child_nodes])
    else
      childNodes = params[:reactParams][:child_nodes]
    end
    tmpRes = {}
    res = {}
    for node in childNodes
      fnode = eval(params[:reactParams][:nodeType]).new

      for a in node
        fnode[a[0]] = a[1]
      end

      # fnode is the parent node
      # ch_nodes are childrens
      ch_nodes = fnode.get_children(nil, nil, session[:user].id, nil, nil)
      tmpRes[fnode.get_name] = ch_nodes

      # cnode = fnode.get_children("created_at", "desc", 2, nil, nil)

    end

    for nodeType in tmpRes.keys
      res[nodeType] =  Array.new

      for node in tmpRes[nodeType]
        tmpObject = {}
        tmpObject["nodeinfo"] = node
        tmpObject["name"] = node.get_name
        tmpObject["type"] = node.type

        if nodeType == 'Courses' || nodeType == "Assignments"
          tmpObject["directory"] = node.get_directory
          tmpObject["creation_date"] = node.get_creation_date
          tmpObject["updated_date"] = node.get_modified_date
          tmpObject["private"] = node.get_private
          instructor_id = node.get_instructor_id
          tmpObject["instructor_id"] = instructor_id
          unless (instructor_id.nil?)
            tmpObject["instructor"] = User.find(instructor_id).name
          else
            tmpObject["instructor"] = nil
          end

          tmpObject["is_available"] = is_available(session[:user], instructor_id) || (session[:user].role_id == 6 && 

Ta.get_my_instructors(session[:user].id).include?(instructor_id) && ta_for_current_course?(node))
          if nodeType == "Assignments"
            tmpObject["course_id"] = node.get_course_id
            tmpObject["max_team_size"] = node.get_max_team_size
            tmpObject["is_intelligent"] = node.get_is_intelligent
            tmpObject["require_quiz"] = node.get_require_quiz
            tmpObject["allow_suggestions"] = node.get_allow_suggestions
            tmpObject["has_topic"] = SignUpTopic.where(['assignment_id = ?', node.node_object_id]).first ? true : false
          end
        end
        res[nodeType] << tmpObject
      end

    end

    respond_to do |format|
      format.html {render json: res}
    end
  end
   def get_children_node_ng
    childNodes = {}
    if params[:reactParams][:child_nodes].is_a? String
      childNodes = JSON.parse(params[:reactParams][:child_nodes])
    else
      childNodes = params[:reactParams][:child_nodes]
    end
    ch_nodes = {}
    for node in childNodes
      # Declaring Foldernode Object as New
      fnode = eval(params[:reactParams][:nodeType]).new
      for a in node
        fnode[a[0]] = a[1]
      end
      # fnode is the parent node
      # ch_nodes are childrens
      ch_nodes[fnode.get_name] = fnode.get_children(nil, nil, session[:user].id, nil, nil)
      # cnode = fnode.get_children("created_at", "desc", 2, nil, nil)
    end
      call_function ="get_children_node_ng"
      #Render JSON of the child nodes
      populate_rows(ch_nodes,call_function)
  end

Refactoring get_children_node_2_ng method

Before Changes After Changes
  def get_children_node_2_ng
    childNodes = {}
    if params[:reactParams2][:child_nodes].is_a? String
      childNodes = JSON.parse(params[:reactParams2][:child_nodes])
    else
      childNodes = params[:reactParams2][:child_nodes]
    end
    tmpRes = {}
    res = []
    fnode = eval(params[:reactParams2][:nodeType]).new
    childNodes.each do |key, value|
      fnode[key] = value
    end

    ch_nodes = fnode.get_children(nil, nil, session[:user].id, nil, nil)
    tmpRes = ch_nodes
    if tmpRes
      for child in tmpRes
        nodeType = child.type
        res2 = {}
        res2["nodeinfo"] = child
        res2["name"] = child.get_name
        res2["key"] = params[:reactParams2][:key]
        res2["type"] = nodeType

        res2["private"] = child.get_private
        res2["creation_date"] = child.get_creation_date
        res2["updated_date"] = child.get_modified_date
        if nodeType == 'CourseNode' || nodeType == "AssignmentNode"
          res2["directory"] = child.get_directory
          instructor_id = child.get_instructor_id
          res2["instructor_id"] = instructor_id
          unless (instructor_id.nil?)
            res2["instructor"] = User.find(instructor_id).name
          else
            res2["instructor"] = nil
          end

          res2["is_available"] = is_available(session[:user], instructor_id) || (session[:user].role_id == 6 && 
Ta.get_my_instructors(session[:user].id).include?(instructor_id) && ta_for_current_course?(child))
          if nodeType == "AssignmentNode"
            res2["course_id"] = child.get_course_id
            res2["max_team_size"] = child.get_max_team_size
            res2["is_intelligent"] = child.get_is_intelligent
            res2["require_quiz"] = child.get_require_quiz
            res2["allow_suggestions"] = child.get_allow_suggestions
            res2["has_topic"] = SignUpTopic.where(['assignment_id = ?', child.node_object_id]).first ? true : false
          end
        end
        res << res2
      end
    end

    respond_to do |format|
      format.html {render json: res}
    end
  end
 def get_children_node_2_ng
    # Second Level of Tree Display with Children Nodes
    childNodes = {}
    if params[:reactParams2][:child_nodes].is_a? String
      childNodes = JSON.parse(params[:reactParams2][:child_nodes])
    else
      childNodes = params[:reactParams2][:child_nodes]
    end

    res = []
    fnode = eval(params[:reactParams2][:nodeType]).new
    childNodes.each do |key, value|
      fnode[key] = value
    end

    ch_nodes = fnode.get_children(nil, nil, session[:user].id, nil, nil)

    call_function = "get_children_node_2_ng"
    populate_rows(ch_nodes, call_function)
  end

Common Methods Added to get_children_node_ng and get_children_node_2_ng controllers

populate_rows

This is a new Common Method for both get_children_node_ng and get_children_node_2_ng that does the functionality of rendering a page with data from all nodes by calling another method populate_1_row(). There is another Method call that happens in this method which as a whole renders the List View.

  def populate_rows(list,call_function) #render page with data for all nodes in list
    if call_function == "get_children_node_ng"
      tmpRes ={}
      tmpRes = list
      res = {}
       for nodeType in tmpRes.keys
        # declaring a new array
        res[nodeType] =  Array.new
        for node in tmpRes[nodeType]
          res[nodeType] << populate_1_row(node)
        end
       end

    else
      tmpRes = list
      res = []
      if tmpRes
        for child in tmpRes
          res_node = {}
          res_node = populate_1_row(child)
          res_node["key"] = params[:reactParams2][:key]
          res << res_node
        end
      end
    end
    page_render(res)
  end

populate_1_row

'This is a new Method that is called from Method populate_row() and fetches all the child node names from respective Controller actions and then populates the tmpObject.

  def populate_1_row(node) #return JSON for 1 Node
    tmpObject = {}
    tmpObject["nodeinfo"] = node
    # all the child nodes names got and put in tmpObject from respective controller actions
    tmpObject["name"] = node.get_name
    tmpObject["type"] = node.type
    if node.type == 'CourseNode' || node.type == "AssignmentNode"
      tmpObject["directory"] = node.get_directory
      tmpObject["creation_date"] = node.get_creation_date
      tmpObject["updated_date"] = node.get_modified_date
      tmpObject["private"] = node.get_private
      instructor_id = node.get_instructor_id
      tmpObject["instructor_id"] = instructor_id
      unless (instructor_id.nil?)
        tmpObject["instructor"] = User.find(instructor_id).name
      else
        tmpObject["instructor"] = nil
      end

      tmpObject["is_available"] = is_available(session[:user], instructor_id) || (session[:user].role_id == 6 && Ta.get_my_instructors(session[:user].id).include?(instructor_id) && ta_for_current_course?(node))
      if node.type == "AssignmentNode"
        tmpObject["course_id"] = node.get_course_id
        tmpObject["max_team_size"] = node.get_max_team_size
        tmpObject["is_intelligent"] = node.get_is_intelligent
        tmpObject["require_quiz"] = node.get_require_quiz
        tmpObject["allow_suggestions"] = node.get_allow_suggestions
        tmpObject["has_topic"] = SignUpTopic.where(['assignment_id = ?', node.node_object_id]).first ? true : false
      end
    end
    tmpObject
  end

page_render

This is also a common Method which integrates the rendering functionality of get_children_node_ng and get_children_node_2_ng making sure both levels are properly populated in the view.'

  def page_render(list) # Common Render Functionality for get_children_node_ng and get_children_node_2_ng methods
    respond_to do |format|
      format.html {render json: list}
    end
  end

Method Removal

There was a Method which dint have any Routes defined in the Routes.rb file and was not called in any of the Controller . After Careful analysis we descided to remove the method from the tree Display Controller.

filter

  def filter
    search = params[:filter_string]
    filter_node = params[:filternode]
    qid = 'filter+'

    if filter_node == 'QAN'
      assignment = Assignment.find_by_name(search)
      if assignment
        assignment_questionnaires = AssignmentQuestionnaire.where(assignment_id: assignment.id)
        if assignment_questionnaires
          assignment_questionnaires.each { |q|  qid << "#{q.questionnaire_id.to_s}+" }
          session[:root] = 1
        end
      end
    elsif filter_node == 'ACN'
      session[:root] = 2
      qid <<  search
    end
    return qid
  end

Removing duplicate methods

Before Changes After Changes
# direct access to questionnaires
  def goto_questionnaires
    node_object = TreeFolder.find_by_name('Questionnaires')
    session[:root] = FolderNode.find_by_node_object_id(node_object.id).id
    redirect_to :controller => 'tree_display', :action => 'list'
  end

  # direct access to review rubrics
  def goto_review_rubrics
    node_object = TreeFolder.find_by_name('Review')
    session[:root] = FolderNode.find_by_node_object_id(node_object.id).id
    redirect_to :controller => 'tree_display', :action => 'list'
  end

  # direct access to metareview rubrics
  def goto_metareview_rubrics
    node_object = TreeFolder.find_by_name('Metareview')
    session[:root] = FolderNode.find_by_node_object_id(node_object.id).id
    redirect_to :controller => 'tree_display', :action => 'list'
  end

  # direct access to teammate review rubrics
  def goto_teammatereview_rubrics
    node_object = TreeFolder.find_by_name('Teammate Review')
    session[:root] = FolderNode.find_by_node_object_id(node_object.id).id
    redirect_to :controller => 'tree_display', :action => 'list'
  end

  # direct access to author feedbacks
  def goto_author_feedbacks
    node_object = TreeFolder.find_by_name('Author Feedback')
    session[:root] = FolderNode.find_by_node_object_id(node_object.id).id
    redirect_to :controller => 'tree_display', :action => 'list'
  end

  # direct access to global survey
  def goto_global_survey
    node_object = TreeFolder.find_by_name('Global Survey')
    session[:root] = FolderNode.find_by_node_object_id(node_object.id).id
    redirect_to :controller => 'tree_display', :action => 'list'
  end

  # direct access to surveys
  def goto_surveys
    node_object = TreeFolder.find_by_name('Survey')
    session[:root] = FolderNode.find_by_node_object_id(node_object.id).id
    redirect_to :controller => 'tree_display', :action => 'list'
  end

  # direct access to course evaluations
  def goto_course_evaluations
    node_object = TreeFolder.find_by_name('Course Evaluation')
    session[:root] = FolderNode.find_by_node_object_id(node_object.id).id
    redirect_to :controller => 'tree_display', :action => 'list'
  end

  # direct access to courses
  def goto_courses
    node_object = TreeFolder.find_by_name('Courses')
    session[:root] = FolderNode.find_by_node_object_id(node_object.id).id
    redirect_to :controller => 'tree_display', :action => 'list'
  end

  # direct access to assignments
  def goto_assignments
    node_object = TreeFolder.find_by_name('Assignments')
    session[:root] = FolderNode.find_by_node_object_id(node_object.id).id
    redirect_to :controller => 'tree_display', :action => 'list'
  end
 # direct access
 def go_to_menu_items
    name = params[:params1]
    if name
      if name == "Review rubrics"
          name = "Review"
        elsif name == "Teammate review rubrics"
          name = "Teammate Review"
        elsif name == "Metareview rubrics"
          name = "Metareview"
        elsif name == "Author feedbacks"
          name = "Author Feedback"
        elsif name == "Global surveys"
          name = "Global Survey"
        elsif name == "Course evaluations"
          name = "Course Evaluation"
        elsif name == "Surveys"
            name = "Survey"
      end
      node_object = TreeFolder.find_by_name(name)
              session[:root] = FolderNode.find_by_node_object_id(node_object.id).id
      if node_object.name == "Courses"
              session[:last_open_tab] = 1
      elsif node_object.name == "Assignments"
              session[:last_open_tab] = 2
      elsif (node_object.id ==1 ||node_object.id ==4 ||node_object.id ==5 ||
              node_object.id ==6 ||node_object.id ==7 ||node_object.id ==8 ||node_object.id ==9||
              node_object.id ==10) # if node_object_name is Questionnaires or its child_nodes
           session[:last_open_tab] = 3   # for Questionnaires and all its childnodes
      end
           redirect_to :controller => 'tree_display', :action => 'list'
    else        # if the passed params is null, redirect to root
           redirect_to "/"
    end

Rspec Test

We have written Rspec tests for the tree_display_controller and have run the same with success.

From the home directory of the application, run the test as "rspec spec/controllers/tree_display_controller_spec.rb"

require 'rails_helper'

describe TreeDisplayController do

describe "#list" do
    it "should not redirect to student_task controller if current user is an instructor" do
      allow(session[:user]).to receive("student?").and_return(false)
      post "list"
      response.should_not redirect_to(list_student_task_index_path)
end
    it "should redirect to student_task controller if current user is a student" do
       allow(session[:user]).to receive("student?").and_return(true)
       post "list"
       response.should redirect_to(list_student_task_index_path)
    end
end
describe "#ta_for_current_mappings?" do
    it "should return true if current user is a TA for current course" do
        allow(session[:user]).to receive("ta?").and_return(true)
    end
end

describe "#populate_rows" do
    let(:dbl) { double }
  before { expect(dbl).to receive(:populate_rows).with(Hash, String)}
     it "passes when the arguments match" do
      dbl.populate_rows({},"")
     end
end

describe "#populate_1_row" do
    let(:dbl) { double }
  before { expect(dbl).to receive(:populate_1_row).with(Node) }
     it "passes when the arguments match" do
        dbl.populate_1_row(Node.new)
     end
  end

  describe "#go_to_menu_items" do
    before do
          allow(nil).to receive(:find_by_node_object_id).and_return(nil)
          allow(nil).to receive(:id).and_return(nil)
          allow(nil).to receive(:name).and_return(true)
    end
      it "should receive Review Rubrics and redirect to list" do
          allow(nil).to receive(:find_by_name).with("Review").and_return(nil)
          get "go_to_menu_items", params1: "Review Rubrics"
          expect(response).to redirect_to(list_tree_display_index_path)
      end
      it "should receive Teammate review rubrics and redirect to list" do
          allow(nil).to receive(:find_by_name).with("Teammate review").and_return(nil)
          get "go_to_menu_items", params1: "Teammate review rubrics"
          expect(response).to redirect_to(list_tree_display_index_path)
      end
      it "should receive Metareview rubrics and redirect to list" do
          allow(nil).to receive(:find_by_name).with("Metareview").and_return(nil)
          get "go_to_menu_items", params1: "Metareview rubrics"
          expect(response).to redirect_to(list_tree_display_index_path)
      end
      it "should receive Author feedbacks and redirect to list" do
          allow(nil).to receive(:find_by_name).with("Author Feedback").and_return(nil)
          get "go_to_menu_items", params1: "Author feedbacks"
          expect(response).to redirect_to(list_tree_display_index_path)
      end
      it "should receive Global surveys and redirect to list" do
          allow(nil).to receive(:find_by_name).with("Global Survey").and_return(nil)
          get "go_to_menu_items", params1: "Global surveys"
          expect(response).to redirect_to(list_tree_display_index_path)
      end
      it "should receive Course evaluations and redirect to list" do
          allow(nil).to receive(:find_by_name).with("Course Evaluation").and_return(nil)
          get "go_to_menu_items", params1: "Course evaluations"
          expect(response).to redirect_to(list_tree_display_index_path)
      end
      it "should receive Surveys and redirect to list" do
          allow(nil).to receive(:find_by_name).with("Survey").and_return(nil)
          get "go_to_menu_items", params1: "Surveys"
          expect(response).to redirect_to(list_tree_display_index_path)
      end
      it "should redirect to root_url if request parameter is invalid" do
          allow(nil).to receive(:find_by_name).with(nil).and_return(nil)
          get "go_to_menu_items"
          expect(response).to redirect_to(root_path)
      end
    end
    describe "#drill" do
      it "redirect to list action" do
           get "drill" , root: 1
           session[:root].should == "1"
           expect(response).to redirect_to(list_tree_display_index_path)
      end
    end
end

References

<references></references>