Commit 8acaaaa

mo khan <mo@mokhan.ca>
2016-07-23 22:43:32
calculate deload after 3 failed workouts.
1 parent a240ef5
app/assets/javascripts/templates/workout_view.ractive
@@ -1,7 +1,7 @@
 {{#if clock}}
   <div class="callout {{alertStatus}}">
-    <p> {{message}} </p>
-    <p> Rest Clock: {{clock}} </p>
+    <p class="text-center"> {{message}} </p>
+    <p class="text-center"> Rest Clock: {{clock}} </p>
   </div>
 {{/if}}
 
app/models/exercise_set.rb
@@ -23,4 +23,12 @@ class ExerciseSet < ApplicationRecord
       "#{(remaining_weight / 2).pretty_print}/side"
     end
   end
+
+  def success?
+    actual_repetitions == target_repetitions
+  end
+
+  def failed?
+    !success?
+  end
 end
app/models/routine.rb
@@ -31,7 +31,9 @@ class Routine < ApplicationRecord
 
   def prepare_sets_for(user, workout)
     exercises.each do |exercise|
-      workout.exercise_sets << program.prepare_sets_for(user, exercise)
+      program.prepare_sets_for(user, exercise).each do |set|
+        workout.add_set(set)
+      end
     end
     workout
   end
app/models/training_history.rb
@@ -21,9 +21,25 @@ class TrainingHistory
     sets.where(workout: last_workout).count
   end
 
-  def last_weight
-    last_successful_set = sets.successful.last
-    last_successful_set.try(:target_weight)
+  def deload?
+    recent_workouts = user.workouts.recent.with_exercise(exercise)
+    if recent_workouts.count >= 3
+      recent_workouts.any? do |workout|
+        workout.sets.work.any?(&:failed?)
+      end
+    else
+      false
+    end
+  end
+
+  def last_weight(successfull_only: false)
+    if successfull_only
+      last_successful_set = sets.successful.last
+      last_successful_set.try(:target_weight)
+    else
+      last_successful_set = sets.last
+      last_successful_set.try(:target_weight)
+    end
   end
 
   def to_line_chart
app/models/user_recommendation.rb
@@ -35,12 +35,24 @@ class UserRecommendation
     recommended_sets > 0 ? recommended_sets : recommendation.sets
   end
 
-  def next_weight
-    last_weight = user.history_for(exercise).last_weight
-    if last_weight.present? && last_weight > 0
-      5.lbs + last_weight
+  def next_weight(deload_percentage: 0.10)
+    history = user.history_for(exercise)
+    if history.deload?
+      last_weight = history.last_weight
+      ten_percent_decrease = (last_weight * deload_percentage).to(:lbs).amount
+      weight_to_deduct = if (ten_percent_decrease % 5) > 0
+        ten_percent_decrease - (ten_percent_decrease % 5) + 5
+      else
+        ten_percent_decrease - (ten_percent_decrease % 5)
+      end
+      last_weight - weight_to_deduct.lbs
     else
-      45.lbs
+      last_weight = history.last_weight(successfull_only: true)
+      if last_weight.present? && last_weight > 0
+        5.lbs + last_weight
+      else
+        45.lbs
+      end
     end
   end
 
app/models/workout.rb
@@ -1,4 +1,5 @@
 class Workout < ApplicationRecord
+  attribute :body_weight, :quantity
   belongs_to :user
   belongs_to :routine
   has_one :program, through: :routine
@@ -10,11 +11,7 @@ class Workout < ApplicationRecord
 
   scope :recent, -> { order(occurred_at: :desc) }
   scope :with_exercise, ->(exercise) do
-    joins(:exercises).where(exercises: { id: exercise.id })
-  end
-
-  def body_weight
-    Quantity.new(read_attribute(:body_weight), :lbs)
+    joins(:exercises).where(exercises: { id: exercise.id }).distinct
   end
 
   def train(exercise, target_weight, repetitions:, set: nil)
@@ -38,6 +35,10 @@ class Workout < ApplicationRecord
     Progress.new(self, exercise)
   end
 
+  def add_set(set)
+    exercise_sets.push(set)
+  end
+
   def each_exercise
     exercises.order(:created_at).distinct.each do |exercise|
       yield exercise
spec/models/program_spec.rb
@@ -64,6 +64,16 @@ describe Program do
         expect(sets.map(&:target_weight).uniq).to match_array([45.lbs])
       end
 
+      it 'deloads you by 10% after 3 consecutive failed workouts' do
+        3.times do
+          workout = create(:workout, user: user, routine: routine_a)
+          5.times { |n| workout.train(squat, 310, repetitions: n) }
+        end
+
+        sets = subject.prepare_sets_for(user, squat).select(&:work?)
+        expect(sets.map(&:target_weight).uniq).to match_array([275.lbs])
+      end
+
       describe "warmup" do
         describe "when the workset is less than 65 lbs" do
           it "returns zero warmup sets" do