master
1class Workout < ApplicationRecord
2 attribute :body_weight, :quantity
3 belongs_to :user
4 belongs_to :routine
5 has_one :program, through: :routine
6 has_many :exercises, through: :exercise_sets
7 has_many :exercise_sets, dependent: :destroy, inverse_of: :workout
8 accepts_nested_attributes_for :exercise_sets
9 delegate :name, to: :routine
10 alias_method :sets, :exercise_sets
11
12 scope :since, ->(date) { after(date) }
13 scope :before, ->(date) { where('occurred_at < ?', date) }
14 scope :after, ->(date) { where('occurred_at > ?', date) }
15 scope :recent, -> { order(occurred_at: :desc) }
16 scope :with_exercise, ->(exercise) do
17 joins(:exercises).where(exercises: { id: exercise.id }).distinct
18 end
19 scope :to_line_chart, -> do
20 joins(:exercise_sets).group(:occurred_at).recent.maximum('exercise_sets.target_weight')
21 end
22
23 def train(exercise, target_weight, repetitions:, set: nil)
24 all_sets = sets.for(exercise).to_a
25 if set.blank? || (exercise_set = all_sets.to_a.at(set)).blank?
26 recommendation = program.recommendation_for(user, exercise)
27 exercise_set = sets.build(
28 type: WorkSet.name,
29 exercise: exercise,
30 target_repetitions: recommendation.repetitions
31 )
32 end
33 exercise_set.update!(
34 actual_repetitions: repetitions,
35 target_weight: target_weight
36 )
37 exercise_set
38 end
39
40 def progress_for(exercise)
41 Progress.new(self, exercise)
42 end
43
44 def add_set(set)
45 exercise_sets.push(set)
46 end
47
48 def each_exercise
49 exercises.order(:created_at).distinct.each do |exercise|
50 yield exercise
51 end
52 end
53
54 def display_status_for(exercise)
55 progress_for(exercise).status
56 end
57
58 def to_hash
59 exercises_hash = sets.includes(:exercise).order(:created_at).group_by(&:exercise).map do |exercise, sets|
60 {
61 id: exercise.id,
62 name: exercise.name,
63 sets: sets.sort_by(&:created_at).map(&:to_hash)
64 }
65 end
66
67 {
68 id: id,
69 body_weight: body_weight,
70 exercises: exercises_hash
71 }
72 end
73end