CSC/ECE 517 Spring 2020 - E2006. Refactor Tree Display Controller
E2006. Refactor tree_display_controller.rb
Project Description
Problem Statement
E2006. Refactor tree_display_controller.rb
Background
The tree_display_controller is responsible for rendering hierarchical lists in the instructor user interface. Here is a sample instructor homepage:
The image below shows that specific questionnaires are nested under different questionnaire categories. This means that the node for a questionnaire has a parent_id that points to a node for a questionnaire category. Similarly, listings of courses and their assignments are hierarchical.
The various rubrics, as well as surveys, are types of questionnaires. So the parent_id of a particular rubric will be the type of rubric (e.g., teammate review) that it is.
The tree_display_controller was 379 lines long, and contained 45 methods. Many of those methods had similar names and were performing very similar functions. In an effort to save code and avoid DRY issues this file was refactored.
This effort reduced the controller to less than 200 lines, 20 public methods (15 of which are necessary scaffold for menu navigation), and 6 private methods.
Goals
From the problem background three main goals were derived to focus on in the refactor of tree display controller:
- Remove unnecessary methods - Search the 45 methods defined in the controller to see where and why they are called. Remove outdated and unused methods, and see where it is fit to merge or replace methods.
- Save code and avoid DRY issues - In addition to removing unnecessary methods, code should be reduced wherever possible to make the controller smaller and easier to read.
- Improve understanding - For all necessary, complex methods in the controller, comments should be added to improve understanding of what methods do. This way, future reviewers won't have to search for implementations to understand the functionality when working on other issues.
Changes
The sections below include a link to the commits where the changes were made following the description. We believe that by providing the links to code changes that we will improve the flow of the wiki while giving a better idea of what the code changes look like in each commit. All code changes can be found in pull request #1698
Make all file scope methods private
Code that is only called within the tree_display_controller.rb
was moved to the private scope. This makes the code easier to read and easier to understand what is getting called outside the controller. Assign private designation to internal methods
Combine folder_node_ng_getter with children_node_ng
folder_node_ng_getter
was being called by the view to return FolderNode.get
. The resulting json of this call was then passed, without modification, into children_node_ng
. Since this was the only place folder_node_ng_getter
was being called it was combined with children_node_ng
to make things easier to read when when viewing controller code. Refactor children_node_ng
Refactor children_node_ng
children_node_ng
was a misleading name. The method has been renamed get_folder_contents
since it returns the contents of each top level folder (assignments, courses, and questionnaires) in json format. In addition to the name change, the get_folder_contents
method was refactored to include the behavior of folder_node_ng_getter
. This addition simplifies the code because the method no longer needs to convert the object that was converted to json back to an object. A single call serialize_folder_to_json
makes the code easier to read instead of chasing nested function calls through initialize_fnode_update_children
which ultimately leads to the same result. Another key change was changing the method from a post to a get, to better represent what it was doing. Changes to tree_display.jsx
and routes.rb
had to be made to account for the name change and method type change. Refactor children_node_ng
Refactor children_node_ng_2
children_node_ng_2
was a misleading name. The method has been renamed get_sub_folder_contents
since it returns the subfolder items for the folders obtained by get_folder_contents
in json format. Like the get_folder_contents
refactor get_sub_folder_contents
was simplified to make a single call to serialize_sub_folder_to_json
making the code easier to read. Again this method was changed from a post to a get, to better represent what it was doing. Changes to tree_display.jsx
and routes.rb
had to be made to account for the name change and method type change. Refactor children_node_ng_2 Rename children_node_2_ng to get_sub_folder_contents Rename serialize_to_json to serialize_sub_folder_to_json
Inline function calls to make json serialization more clear
Where it could be done without making the existing functions unwieldy functions that updated json properties were moved up one level. This makes it easier to see in one place what properties are being modified by the serialization functions. Inline function calls to make json serialization more clear
Simplify checks for determining a users access to view a course
With guidance from Dr. Gehringer it was determined a TA should have access to view all items for a given course if and only if they are mapped to that course. Likewise a instructor should be able to view all of the items for courses they teach. Admins and super admins have access to all items on the website. These facts allowed us to greatly simplify the checks necessary to determine if a course was available to the current user and if it should be private or not. Simplified is_available checks Removed unused is_available checks
Collapse 'goto' methods
In the legacy code found in tree_display_controller.rb
, 60 lines are dedicated to the 12 methods related to traversing the menu system. 11 of the methods call the goto_controller()
method with different values. Those 11 methods were condensed into single line methods with one overarching comment to describe them. This change makes the code easier to read, since each of the 11 methods condensed carry out the same functionality, and easier to understand since we have added in a better comment for understanding what the code does (Goal 3). This also saved 41 lines of code in the controller (Goal 2). Compact gotos
Remove unnecessary code to sort assignments by instructor and creation date
By default assignments are received from FolderNode.get
sorted by instructor and creation date. There is no need to resort this object. Remove unnecessary code to sort assignments by instructor and creation date
Remove unused functions
By searching for the implementations of all functions in the controller we were able to recognize some of them as being unused and remove them (Goal 1). Others became unused once refactoring was completed.
filter()
filter_node_is_qan()
These methods were both removed because they were only used in the page_header partial for tree display, which was removed approximately 3 years prior.
courses_assignments_obj()
confirm_notifications_access()
child_nodes_from_params()
res_node_for_child()
These methods are not used in the app.
update_tmp_obj()
This method was used only once in the app, and it was in the tree display controller, since the purpose of the method was aligned with the purpose of the serialize_to_json
method which called it there was no reason to write a new method to call. Especially since the update_tmp_obj
method was only making minor changes to the json.
bridge_to_is_available()
action()
These methods are not called in the app. References to these methods were removed from routes.rb
Test Plan
All tests described below have been implemented in the tree_display_controller_spec.rb file. Since this project was focused on refactoring the tree_display_controller.rb code, and not on adding any functionality, we have edited the spec file to accommodate for our changes. All changes to the spec file correspond to the refactoring that we have done.
#list
should not redirect if current user is an instructor.- A user is defined to be an instructor. When the
get "list"
method is called, the response should not redirect to the tree_display/list
#list
should not redirect if current user is a TA.- A user is defined to be an instructor. When the
get "list"
method is called, the response should not redirect to the tree_display/list
#list
should redirect to student_task#list if current user is a student- A user is defined to be a student. Instead of redirecting to the tree_display list, it should redirect to the student_task list.
#list
should redirect to login page if current user is nil.- This is a catch all for if a user somehow directs to the list without signing in, they shouldn't be able to see anything without signing in first.
#ta_for_current_mappings?
should return true if the current user is a TA for current course- This test should check that the method properly returns true if it receives a ta as the user.
#drill
should redirect to list action- The drill method should redirect to the tree_display controller with the list action.
GET #session_last_open_tab
should return a status of 200.- The HTTP status 200 is the OK SUCCESS status to show that the get request succeeds.
GET #set_session_last_open_tab
should return a status of 200.- The HTTP status 200 is the OK SUCCESS status to show that the get request succeeds.
GET #get_folder_contents
should return a list of course objects(private) as a json.- When there is a course (private) and an assignment defined, the get_folder_contents method should match the json file provided in the test.
GET #get_folder_contents
should return an empty list if no courses- When the public and private courses have been deleted/aren't present, then the list returned should be empty, consisting of 'Courses: []'
GET #get_folder_contents
should return a list of course objects(public) as a json.- When there is a course (public) and an assignment defined, the get_folder_contents method should match the json file provided in the test.
GET #get_folder_contents for TA
should return an empty array if the logged in user is not a TA.- Edge case testing to ensure that a user with the role of student results in an empty array.
GET #get_folder_contents for TA
should return a list of course objects the TA is supposed to TA in as json.- If the logged in user is a TA, then return should be a json of all courses that the user is a ta for.
GET #get_folder_contents for TA
should return an empty list when there is no mapping between a ta and a course.- If the TA is not mapped to a course then the return should be empty.
GET #get_folder_contents for TA
should return only courses that a TA is a TA for. It should not return any courses that the user is a student in, but not a TA in.- Edge case test for when the user is a student in some classes, but a TA in others.
GET #get_folder_contents for TA
should return only the course he/she is TA of when the TA is a student of the same course.- Edge case test for a student in a course also being a TA, most likely because of an error in assignment.
GET #get_folder_contents for TA
returns only the assignments which belongs to the course he/she is TA of.- All assignments in the courses that the TA is assigned to should be returned.
GET #get_folder_contents for TA
should return an empty list if none of the assignments belong to the course he/she is TA of.- Edge case test for when there are assignments, but they don't belong to courses which he/she is a TA.
Test Results
Team Information
Brooks Anderson
Rick Holloway
PJ Loheide
Special thanks to our mentor and professor: Dr. Edward Gehringer