class Race

A Race is essentionally a collection of Results labelled with a Category. Races must belong to a parent Event.

Races only have some of their attributes populated. These attributes are listed in the result_columns Array.

People use say “category” where we use Race in code. Could rename this EventCategory.

Race result_columns: populated columns displayed on results page. Usually Result attributes, but also creates virtual "custom" columns.

Constants

DEFAULT_RESULT_COLUMNS

Public Instance Methods

<=>(other) click to toggle source

By category name

# File app/models/race.rb, line 307
def <=>other
  category.name <=> other.category.name
end
==(other) click to toggle source
# File app/models/race.rb, line 319
def==(other)
  return false unless other.is_a?(self.class)
  unless other.new_record? or new_record?
    return other.id == id
  end
  category == other.category
end
bar_points() click to toggle source

Defaults to Event’s BAR points

# File app/models/race.rb, line 30
def bar_points
  self[:bar_points] || self.event.bar_points
end
bar_points=(value) click to toggle source

0..3

# File app/models/race.rb, line 35
def bar_points=(value)
  if value == self.event.bar_points or value.nil?
    self[:bar_points] = nil
  elsif value.to_i == value.to_f
    self[:bar_points] = value
  else
    raise ArgumentError, "BAR points must be an integer, but was: #{value}"
  end
end
calculate_members_only_places!() click to toggle source
# File app/models/race.rb, line 213
def calculate_members_only_places!
  event_notification_was_enabled = event.notification_enabled?
  event.disable_notification!
  begin
    # count up from zero
    last_members_only_place = 0
    # assuming first result starting at zero+one (better than sorting results twice?)
    last_result_place = 0
    results.sort.each do |result|
      place_before = result.members_only_place.to_i
      result.members_only_place = ''
      if result.place.to_i > 0         
        if ((result.person.nil? || (result.person && result.person.member?(result.date))) && !non_members_on_team(result))
          # only increment if we have moved onto a new place
          last_members_only_place += 1 if (result.place.to_i != last_members_only_place && result.place.to_i!=last_result_place)
          result.members_only_place = last_members_only_place.to_s
        end
        # Slight optimization. Most of the time, no point in saving a result that hasn't changed
        result.update_attribute('members_only_place', result.members_only_place) if place_before != result.members_only_place 
        # store to know when switching to new placement (team result feature)
        last_result_place = result.place.to_i
      end
    end
  ensure
    event.enable_notification! if event_notification_was_enabled
  end
end
calculate_result_columns!() click to toggle source
# File app/models/race.rb, line 104
def calculate_result_columns!
  self.result_columns = result_columns_or_default
  result_columns.delete_if do |result_column|
    results.all? do |result|
      value = result.send(result_column)
      value.blank? || value == 0 || value == 0.0
    end
  end
  save!
end
category_friendly_param() click to toggle source
# File app/models/race.rb, line 62
def category_friendly_param
  category.try :friendly_param
end
category_name() click to toggle source
# File app/models/race.rb, line 58
def category_name
  category.try :name
end
category_name=(name) click to toggle source
# File app/models/race.rb, line 45
def category_name=(name)
  if name.blank?
    self.category = nil
  else
    self.category = Category.new(:name => name)
  end
  category.try :name
end
create_result_before(result_id) click to toggle source
# File app/models/race.rb, line 265
def create_result_before(result_id)
  results.sort!
  if results.empty?
    return results.create(:place => "1")
  end
  
  if result_id
    result = Result.find(result_id)
    place = result.place
    start_index = results.index(result)
    for index in start_index...(results.size)
      if results[index].place.to_i > 0
        results[index].place = (results[index].place.to_i + 1).to_s
        results[index].save!
      end
    end
  else
    result = results.last
    if result.place.to_i > 0
      place = result.place.to_i + 1
    else
      place = result.place
    end
  end
  
  results.create(:place => place)
end
custom_columns() click to toggle source
# File app/models/race.rb, line 149
def custom_columns
  self[:custom_columns] ||= []
end
date() click to toggle source
# File app/models/race.rb, line 87
def date
  event.try :date
end
dates_of_birth() click to toggle source

Range of #dates_of_birth of people in this race

# File app/models/race.rb, line 82
def dates_of_birth
  raise(ArgumentError, 'Need category to calculate dates of birth') unless category
  Date.new(date.year - category.ages.end, 1, 1)..Date.new(date.year - category.ages.begin, 12, 31)
end
destroy_result(result) click to toggle source
# File app/models/race.rb, line 293
def destroy_result(result)
  place = result.place
  results.sort!
  start_index = results.index(result) + 1
  for index in start_index...(results.size)
    if results[index].place.to_i > 0
      results[index].place = results[index].place.to_i - 1
      results[index].save!
    end
  end
  result.destroy
end
discipline() click to toggle source
# File app/models/race.rb, line 54
def discipline
  self.event.discipline if event
end
field_size() click to toggle source

Incorrectly doubles tandem and other team events’ field sizes

# File app/models/race.rb, line 96
def field_size
  if self[:field_size].present? && self[:field_size] > 0
    self[:field_size]
  else
    results.size
  end
end
find_associated_records() click to toggle source

Ensure child team and people are not duplicates of existing records Tricky side effect – external references to new association records (category, bar_category, person, team) will not point to associated records FIXME Handle people with only a number

# File app/models/race.rb, line 161
def find_associated_records
  if category && (category.new_record? || category.changed?)
    if category.name.blank?
      self.category = nil
    else
      existing_category = Category.find_by_name(category.name)
      self.category = existing_category if existing_category
    end
  end
end
full_name() click to toggle source

Combine with event name

# File app/models/race.rb, line 71
def full_name
  if name == event.full_name
    name
  elsif event.full_name[name]
    event.full_name
  else
    "#{event.full_name}: #{name}"
  end
end
has_result(row_hash) click to toggle source
# File app/models/race.rb, line 172
def has_result(row_hash)
  if row_hash["place"].present? && row_hash["place"] != "1" && row_hash["place"] != "0"
    return true
  end
  if row_hash["person.first_name"].blank? && 
     row_hash["person.last_name"].blank? &&
     row_hash["person.road_number"].blank? &&
     row_hash["team.name"].blank?
    return false
  end
  true
end
hash() click to toggle source
# File app/models/race.rb, line 311
def hash
  if new_record?
    category.hash
  else
    id
  end
end
name() click to toggle source
# File app/models/race.rb, line 66
def name
  self.category_name
end
non_members_on_team(result) click to toggle source
# File app/models/race.rb, line 241
def non_members_on_team(result)
  non_members = false
  # if this is undeclared in environment.rb, assume this rule does not apply
  exempt_cats = RacingAssociation.current.exempt_team_categories
   if (exempt_cats.nil? || exempt_cats.include?(result.race.category.name))
     return non_members
   else
     other_results_in_place = Result.all( :conditions => ["race_id = ? and place = ?", result.race.id, result.place])
     other_results_in_place.each { |orip|
        unless orip.person.nil?
          if !orip.person.member?(result.date)
           # might as well blank out this result while we're here, saves some future work
           result.members_only_place = ''
           result.update_attribute 'members_only_place', result.members_only_place
           # could also use other_results_in_place.size if needed for calculations
           non_members = true
          end
        end
     }
     # still false if no others found, or all are members, or could not be determined (non-person)
     non_members
   end
 end
place_results_by_points(break_ties = true, ascending = true) click to toggle source

Sort results by points, assign places Save! each result after place is set

# File app/models/race.rb, line 187
def place_results_by_points(break_ties = true, ascending = true)
  results.each(&:calculate_points)

  results.sort! do |x, y| 
    x.compare_by_points(y)
  end

  if !ascending
    results.reverse!
  end

  previous_result = nil
  results.each_with_index do |result, index|
    if index == 0
      result.place = 1
    else
      if results[index - 1].compare_by_points(result, break_ties) == 0
        result.place = results[index - 1].place
      else
        result.place = index + 1
      end
    end
    result.save!
  end
end
result_columns=(value) click to toggle source
# File app/models/race.rb, line 115
def result_columns=(value)
  if value && value.include?("name")
    name_index = value.index("name")
    value[name_index] = "first_name"
    value.insert(name_index + 1, "last_name")
  end

  if value && value.include?("place") && value.first != "place"
    value.delete("place")
    value.insert(0, "place")
  end
  self[:result_columns] = value
end
result_columns_or_default() click to toggle source

Default columns if empty

# File app/models/race.rb, line 130
def result_columns_or_default
  self.result_columns || DEFAULT_RESULT_COLUMNS.dup
end
result_columns_or_default_for_editing() click to toggle source

Ugh. Better here than a controller or helper, I guess.

# File app/models/race.rb, line 135
def result_columns_or_default_for_editing
  columns = result_columns_or_default
  columns.map! do |column| 
    if column == "first_name" || column == "last_name"
      "name"
    else
      column
    end
  end
  columns << "bar" #if RacingAssociation.current.competitions.include?(:bar)
  columns.uniq!
  columns
end
symbolize_custom_columns() click to toggle source
# File app/models/race.rb, line 153
def symbolize_custom_columns
  self.custom_columns.map! { |col| col.to_s.to_sym }
end
to_s() click to toggle source
# File app/models/race.rb, line 327
def to_s
  "#<Race #{self.id} #{self[:event_id]} #{self[:category_id]} >"
end
year() click to toggle source
# File app/models/race.rb, line 91
def year
  event && event.date && event.date.year
end