CSC/ECE 517 Fall 2022 - E2254: Refactor teams controller.rb
Introduction
In this project we refactored teams_controller.rb and some tests associated with it. Before we worked on it, teams_controller.rb had some problems that violated some essential Rails design principles. Some methods have been moved to the teams.rb model class. Some duplicate code was removed. We added some comments for readability. And, we fixed tests to be more consistent with the program and execution.
Issues Fixed
- Added more comments and briefly explained the functionality of custom methods like
action_allowed
, andlist
- Changed method name of
create_teams
to a better name:randomize_teams
- Found areas in the code where the DRY principle can be applied and did so
- The delete method manipulates a waitlist! This needs to be done in a model class, e.g., SignedUpTeam. And also check if this code is already present in the model or not. Explore the code base to find where else waitlist is manipulated.
- Changed the delete method to use the existing Waitlist.remove_from_waitlists method to handle removing the deleted team from all waitlists
- Removed all extra added gems
- Renamed variable signUps to signups because it's a noun
- Actually ended up removing this variable in the process of doing fix 4 above
- Moved list copying code from the
inherit
method to be a class method of the Team model:copy_teams_to_collection
. Also replaced identical code in bequeath_all to also use this class method. - Changed the name of the
inherit
method tocopy_to_assignment
so the name is more descriptive of it's purpose - Removed nested if statments and removed other return points from bequeath_all
- Removed unnecessary comments for methods like
update
and added meaningful comments to other methods
Files Changed
- app/controllers/teams_controller.rb
- app/models/team.rb
- app/views/teams/new.html.erb
- config/locales/en_US.yml
- config/locales/en_IN.yml
- config/routes.rb
- spec/controllers/teams_controller_spec.rb
- spec/controllers/airbrake_exception_errors_controller_tests_spec.rb
Changes
Fix #2
The create_teams
method's name poorly reflected it's actual function. The function takes a group of students from an assignment or course and creates randomized teams. To reflect this, the method was renamed to randomize_teams
and a comment was added briefly describing the function. This also needed to be updated in the rspec test teams_controller_spec.rb
:
describe 'create teams method' do context 'when correct parameters are passed' do it 'creates teams with random names' do allow(ExpertizaLogger).to receive(:info).and_return(nil) ... user_session = { user: instructor, team_type: 'Assignment' } result = get :randomize_teams, params: request_params, session: user_session # status code 302: Redirect url ... end end end
Fix #3
Several places used a complicated line to find the parent of a team. The parent is either a Course
or an Assignment
. The type of parent is stored in the session
and the id
of the parent in the params
. We created two new private methods, team_type
and team_parent
to DRY out the code. The team_type
method returns either Course
or Assignment
and the team_parent
method returns the the actual parent rather than the model.
# Gets the model representing the parent of the team def team_type if session[:team_type] == 'Assignment' Assignment elsif session[:team_type] == 'Course' Course end end # Finds the object containing the students # which the team will be generated from def team_parent @team_parent ||= team_type.find(params[:id]) end
Fixes #4 and #6
Removed the following if statement editing a waitlist in a controller and replaced it with Waitlist.remove_from_waitlists(@team.id)
.
# if @signed_up_team == 1 && !@signUps.first.is_waitlisted # this team hold a topic # # if there is another team in waitlist, make this team hold this topic # topic_id = @signed_up_team.first.topic_id # next_wait_listed_team = SignedUpTeam.where(topic_id: topic_id, is_waitlisted: true).first # # if slot exist, then confirm the topic for this team and delete all waitlists for this team # SignUpTopic.assign_to_first_waiting_team(next_wait_listed_team) if next_wait_listed_team # end
In the process of making this change, the unused @signUps
variable is removed, taking care of Fix #6 as well.
The change to being able to delete from the waitlist needed to be accounted for in the teams_controller_spec.rb
rspec test, which can be seen here:
context 'when called and team is not nil and it does not hold a topic' do it 'deletes the team' do allow(Waitlist).to receive(:remove_from_waitlists).and_return(nil) ... end end
The change in how things were deleted from waitlists and how things were deleted from signed up teams led to issues with rspec testing in airbrake_exception_errors_controller_tests_spec.rb
. To fix this, we allowed functionality to account for what was changed:
it 'will delete the team if current team did not involve in any other reviews' do ... controller.session[:team_type] = 'Assignment' allow(SignedUpTeam).to receive(:destroy).and_return(nil) allow(Waitlist).to receive(:remove_from_waitlists).and_return(nil) allow(Team).to receive(:find).with(any_args).and_return(team) allow(Team).to receive(:find_by).with(any_args).and_return(team) ... end
Fixes #7 and #8
One of the main changes made to implement this was in Team.rb
where the class method copy_teams_to_collection
was added.
# E2254 : This method copies a list of teams to another collection. It is mainly # used in the Team model for copy_to_assignment and bequeath_all for the purpose of copying # teams from assignments to courses and vice versa. def self.copy_teams_to_collection(teams, recipient_collection_id) teams.each do |team| team.copy(recipient_collection_id) end end
This method was called in teams_controller.rb
in the copy_to_assignment
(method used to be named inherit
) and bequeath_all
methods.
def copy_to_assignment ... if teams.empty? flash[:note] = 'No teams were found when trying to copy to assignment.' else Team.copy_teams_to_collection(teams, assignment.id) end ... end def bequeath_all ... teams = assignment.teams Team.copy_teams_to_collection(teams, course.id) flash[:note] = teams.length.to_s + ' teams were successfully copied to "' + course.name + '"' ... end
Fix #9
Refactored bequeath_all to get rid of all the nested if statements
# Copies existing teams from an assignment to a # course if the course doesn't already have teams def bequeath_all assignment = Assignment.find(params[:id]) course = Course.find(assignment.course_id) if assignment.course_id if !assignment.course_id flash[:error] = 'No course was found for this assignment.' elsif course.course_teams.any? flash[:error] = 'The course already has associated teams' else teams = assignment.teams Team.copy_teams_to_collection(teams, course.id) flash[:note] = teams.length.to_s + ' teams were successfully copied to "' + course.name + '"' end redirect_to controller: 'teams', action: 'list', id: assignment.id end
Also, the multiple returns have been removed from the method. The redirect and return for the check to ensure a course team was being used was moved to it's own method:
# Redirects if the team is not a CourseTeam def ensure_course_team if session[:team_type] == 'Course' flash[:error] = 'Invalid team type for bequeathal' redirect_to controller: 'teams', action: 'list', id: params[:id] end end
and specified to run at before the bequeath_all
method at the start of the file:
before_action :ensure_course_team, only: %i[bequeath_all]