# == Schema Information # # Table name: completions # # id :integer not null, primary key # completed :boolean # display_relative_time :string # display_time_from_start :string # missing_pieces :integer # projected_time :integer # remaining_pieces :integer # time_seconds :integer # created_at :datetime not null # updated_at :datetime not null # contest_id :integer not null # contestant_id :integer not null # message_id :integer # puzzle_id :integer not null # # Indexes # # index_completions_on_contest_id (contest_id) # index_completions_on_contestant_id (contestant_id) # index_completions_on_message_id (message_id) # index_completions_on_puzzle_id (puzzle_id) # # Foreign Keys # # contest_id (contest_id => contests.id) # contestant_id (contestant_id => contestants.id) # message_id (message_id => messages.id) # puzzle_id (puzzle_id => puzzles.id) # class Completion < ApplicationRecord include ContestsHelper belongs_to :contest belongs_to :contestant belongs_to :puzzle belongs_to :message, optional: true has_one :offline, dependent: :destroy before_save :clean_pieces before_save :compute_projected_time validates :display_time_from_start, presence: true, format: { with: /\A(((\d\d|\d):\d\d|\d\d|\d):\d\d|\d\d|\d)\z/ }, if: -> { completed || offline.present? } validates :remaining_pieces, presence: true, if: -> { !completed } validates :contestant_id, uniqueness: { scope: :puzzle }, if: -> { contest.puzzles.size == 1 } validates :puzzle_id, uniqueness: { scope: :contestant }, if: -> { contest.puzzles.size > 1 } validates :remaining_pieces, numericality: { only_integer: true }, if: -> { remaining_pieces.present? } validate :remaining_pieces_is_correct, if: -> { remaining_pieces.present? } def remaining_pieces_is_correct if self.remaining_pieces > self.puzzle.pieces errors.add(:remaining_pieces, "Cannot be greater than the number of pieces for this puzzle") end end def add_time_seconds if display_time_from_start.present? arr = display_time_from_start.split(":") if arr.size == 3 self.time_seconds = arr[0].to_i * 3600 + arr[1].to_i * 60 + arr[2].to_i elsif arr.size == 2 self.time_seconds = arr[0].to_i * 60 + arr[1].to_i elsif arr.size == 1 self.time_seconds = arr[0].to_i end else if self.contest.duration_seconds.present? self.time_seconds = self.contest.duration_seconds else self.time_seconds = 2 * 3600 end self.display_time_from_start = display_time(self.time_seconds) end end def clean_pieces if self.completed self.remaining_pieces = nil else self.missing_pieces = nil if !self.offline.present? self.display_time_from_start = nil end end end def compute_projected_time add_time_seconds if self.completed self.projected_time = self.time_seconds else assembled_time = self.time_seconds assembled_pieces = self.puzzle.pieces - self.remaining_pieces pieces_per_second = assembled_pieces.to_f / assembled_time.to_f self.projected_time = assembled_time + Integer(self.remaining_pieces.to_f / pieces_per_second) end end end