Last night I merged a large work in progress branch into StuffToDo so the refactoring I wanted to do wasn’t available anymore. But there’s always a replacement to be found (aka: always some bad code to fix).
The Refactoring
A few days ago I did some refactoring to StuffToDo#available
in order to remove some of the duplication. Today I finally got sick of looking at the remaining duplication and overhauled the method’s logic.
Before
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
# app/models/stuff_to_do.rb class StuffToDo :status, :conditions => conditions_for_available(:user, user.id), :order => 'created_on DESC') elsif filter[:status] status = filter[:status] issues = Issue.find(:all, :include => :status, :conditions => conditions_for_available(:status, status.id), :order => 'created_on DESC') elsif filter[:priority] priority = filter[:priority] issues = Issue.find(:all, :include => [:status, :priority], :conditions => conditions_for_available(:priority, priority.id), :order => 'created_on DESC') elsif filter[:projects] # TODO: remove 'issues' naming issues = active_and_visible_projects.sort end next_issues = StuffToDo.find(:all, :conditions => { :user_id => user.id }).collect(&:stuff) return issues - next_issues end def self.conditions_for_available(filter_by, record_id) conditions_builder = ARCondition.new(["#{IssueStatus.table_name}.is_closed = ?", false ]) case filter_by when :user conditions_builder.add(["assigned_to_id = ?", record_id]) when :status conditions_builder.add(["#{IssueStatus.table_name}.id = (?)", record_id]) when :priority conditions_builder.add(["#{Enumeration.table_name}.id = (?)", record_id]) end conditions_builder.conditions end end |
After
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
class StuffToDo [:status, :priority], :conditions => conditions_for_available(filter, filter.id), :order => 'created_on DESC') end next_issues = StuffToDo.find(:all, :conditions => { :user_id => user.id }).collect(&:stuff) return issues - next_issues end def self.conditions_for_available(filter_by, record_id) conditions_builder = ARCondition.new(["#{IssueStatus.table_name}.is_closed = ?", false ]) case when filter_by.is_a?(User) conditions_builder.add(["assigned_to_id = ?", record_id]) when filter_by.is_a?(IssueStatus) conditions_builder.add(["#{IssueStatus.table_name}.id = (?)", record_id]) when filter_by.is_a?(Enumeration) conditions_builder.add(["#{Enumeration.table_name}.id = (?)", record_id]) end conditions_builder.conditions end end |
Review
The major change was to switch from using a Hash as the input for the “Record type” and “Record” to just using the Record itself. #available
only checked the record type to figure out what to pass to #conditions_for_available
. But each record already has it’s type embedded into it (called a Class) so this was just extra data. Now #available
only branches if the record is a Project, otherwise it ships the data down to #conditions_for_available
.
Also note that this did change #available
‘s method signature. I didn’t include the changes in the caller but it also made things a lot simpler there too. If you’re interested, the commit shows the controller changes.