CSC/ECE 517 Spring 2022 - E2216: Refactor late policies controller
Background
The later policies controller file manages the SCRUM from late policies. Chiefly, the file checks if new or updated late policies are valid policies, in that they do not have the same name as an already existing policy, does not have a late penatly per unit time that surpasses the max late penalty, and does not have a late penalty surpassing 100.
Team Members
- Wyatt Plaga (wgplaga@ncsu.edu)
- Sujith Tumma (stumma2@ncsu.edu)
- Shawn Salekin (ssaleki@ncsu.edu)
Description about project
This wiki describes the work done to refactor late_policies_controller.rb. The main focus of the work went into removing code duplication, as well as simplifying the code for readability, for the create and update methods. This also includes adding code comments for understandibility.
Files Involved
File Modified:
- app/controllers/late_policies_controller.rb
- app/views/late_policies/new.html.erb
- app/views/late_policies/_form.html.erb
- spec/controllers/late_policies_controller_spec.rb
- db/schema.rb
File Added:
- db/migrate/20220321162332_add_private_to_late_policies.rb
Test Plan
This is a refactoring project, so performed manual tests to ensure the functionalities did not change. Here is how you can test it manually.
- Navigate over to the late policies index page: http://152.7.98.82:9090/late_policies
- Create a new policy. Try different input combinations, some valid or invalid. Keep an eye for the error messages
- Try updating the policy
- Try giving the same name to two different policies and see if you get proper error message
- Delete policies.
- Additionally, if you are able to log in as a different instructor, you should not see someone else's privately created
policies.
If all of these changes work as intended, we should be good.
Code Issues
1. All the late policies will show up on the index page, not just policies created by the current instructor. Need to create public & private late policies. Try to leverage code for private and public courses, assignments, and questionnaires.
2. create and update have some duplicate code. Fix that using a partial, _form.
3. Both create and update need comments and a better identifier naming.
4. Reduce code duplication. Find a way to make the code more DRY
5. Line 64: The if condition can be simplified.
6. Improve the variable name for same_policy_name. (Boolean variables can be named in a better way)
7. Add method comments
8. Find the use of instance variables in create and update method? Do we really need it? Can it be made local variables instead?
Code Changes
1. All the late policies will show up on the index page, not just policies created by the current instructor. Need to create public & private late policies. Try to leverage code for private and public courses, assignments, and questionnaires
Current code:
(No such code exists)
Modifications:
- add a column named 'private' on to the LatePolicy model - In the controller#index method, filter the results by private != 0 or instructor_id = current_user_id
2. create and update have some duplicate code. Fix that using a partial, _form.
Filename: app/views/late_policies/new.html.erb
Current Code:
<%= form_for @late_policy, :url => { :action => "create" } do |f| %>
<%= error_messages_for @late_policy %>
<p>
<label for="late_policy_name">Late policy name:</label><label style="color: #ff0000;">*</label><br/>
<%= f.text_field 'policy_name' %>
</p>
<p>
<label for="late_policy_penalty_points_per_unit">Penalty points per unit:</label><label style="color: #ff0000;">*</label><br/>
<%= f.text_field 'penalty_per_unit' %>
</p>
<p>
<label for="penalty_unit">Penalty unit:</label><label style="color: #ff0000;">*</label><br/>
<!--select name=<='late_policy[:penalty_unit]'%>>
<option value='Minute' selected>Minute</option>
<option value='Hour' >Hour</option>
<option value='Day' >Day</option>
</select-->
<% @units= %w[Minute Hour Day]%>
<%= f.select "penalty_unit", @units %>
</p>
<p>
<label for="late_policy_penalty_maximum">Maximum penalty:</label><label style="color: #ff0000;">*</label><br/>
<%= f.text_field 'max_penalty' %>
</p>
Modifications:
<%= form_for @penalty_policy, :url => { :action => "create" } do |f| %>
<%= error_messages_for @penalty_policy %>
<%= render partial: 'form', locals: { f: f } %>
3. Both create and update need comments and a better identifier naming.
Current identifiers names:
* invalid_penalty_per_unit (Problem with this is ,try to read "!invalid_penalty_per_unit". So, "valid_penalty" increases the readability. ) * policy_name_exists
Modifications:
Got rid of both identifier names and implemented functions that validate input and check the duplicity of late policy name * valid_penalty * duplicate_name_check
4. Reduce code duplication. Find a way to make the code more DRY
Extracted the validation done in both create and update into a seperate method. This reduced repition between the two methods. See part 5.
5. Line 64: The if condition can be simplified.
Origional Code:
invalid_penalty_per_unit = params[:late_policy][:max_penalty].to_i < params[:late_policy][:penalty_per_unit].to_i
flash[:error] = 'The maximum penalty cannot be less than penalty per unit.' if invalid_penalty_per_unit
same_policy_name = false
# penalty name should be unique
if same_policy_name != LatePolicy.check_policy_with_same_name(params[:late_policy][:policy_name], instructor_id)
flash[:error] = 'A policy with the same name already exists.'
same_policy_name = true
end
# maximum penalty cannot be greater than equal to 100
if params[:late_policy][:max_penalty].to_i >= 100
flash[:error] = 'Maximum penalty cannot be greater than or equal to 100'
invalid_max_penalty = true
end
if !invalid_penalty_per_unit && !same_policy_name && !invalid_max_penalty
@late_policy = LatePolicy.new(late_policy_params)
@late_policy.instructor_id = instructor_id
begin
@late_policy.save!
flash[:notice] = 'The late policy was successfully created.'
redirect_to action: 'index'
rescue StandardError
flash[:error] = 'The following error occurred while saving the late policy: '
redirect_to action: 'new'
end
else
redirect_to action: 'new'
end
Modifications:
def validate_input(is_update=false)
# Validates input for create and update forms
max_penalty = params[:late_policy][:max_penalty].to_i
penalty_per_unit = params[:late_policy][:penalty_per_unit].to_i
valid_penalty, error_message = true, nil
valid_penalty, error_message = duplicate_name_check(is_update)
prefix = is_update ? "Cannot edit the policy. " : ""
#This check validates the maximum penalty.
if max_penalty < penalty_per_unit
error_message = prefix + 'The maximum penalty cannot be less than penalty per unit.'
valid_penalty = false
end
#This check validates the penalty per unit for a late policy.
if penalty_per_unit < 0
error_message = 'Penalty per unit cannot be negative.'
valid_penalty = false
end
# This checks maximum penalty does not exceed 100.
if max_penalty >= 100
error_message = prefix + 'Maximum penalty cannot be greater than or equal to 100'
valid_penalty = false
end
return valid_penalty, error_message
end
6. Improve the variable name for same_policy_name. (Boolean variables can be named in a better way)
Current identifiers names:
same_policy_name
Modifications:
Got rid of this identifier by replacing it with a function named "duplicate_name_check"
7. Add method comments
No comments
Modifications:
Added comments for all the methods to increase the readability of the code.
GitHub links
Link to Expertiza repository: here
Link to the forked repository: here