Commit 6a1bc50
Changed files (68)
app
assets
javascripts
templates
views
models
views
exercise_workouts
layouts
profiles
programs
recommendations
routines
training_sessions
config
db
migrate
spec
controllers
features
javascripts
models
routing
support
app/assets/javascripts/templates/training_session_view.ractive → app/assets/javascripts/templates/workout_view.ractive
@@ -1,5 +1,5 @@
<div class="row">
- {{#each training_session.exercises}}
+ {{#each workout.exercises}}
<div class="panel small-12 columns">
<h3>{{name}}</h3>
{{#each sets}}
app/assets/javascripts/views/training_session_view.js.coffee → app/assets/javascripts/views/workout_view.js.coffee
@@ -1,9 +1,9 @@
-class Stronglifters.TrainingSessionView extends Ractive
- template: RactiveTemplates["templates/training_session_view"]
+class Stronglifters.WorkoutView extends Ractive
+ template: RactiveTemplates["templates/workout_view"]
oninit: ->
@on 'updateProgress', (event) -> @updateProgress(event)
- @observe 'training_session.exercises.*.sets.*', (newValue, oldValue, keypath) ->
+ @observe 'workout.exercises.*.sets.*', (newValue, oldValue, keypath) ->
@refreshStatus(newValue, oldValue, keypath)
updateProgress: (event) ->
app/controllers/application_controller.rb
@@ -6,9 +6,9 @@ class ApplicationController < ActionController::Base
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
rescue_from ActiveRecord::RecordNotFound, with: :record_not_found
- helper_method :feature_available?
+ helper_method :feature_enabled?
- def feature_available?(feature)
+ def feature_enabled?(feature)
return true if Rails.env.test?
$flipper[feature.to_sym].enabled?(current_user)
end
app/controllers/training_sessions_controller.rb
@@ -1,35 +0,0 @@
-class TrainingSessionsController < ApplicationController
- def index
- @training_sessions = paginate(
- current_user.
- training_sessions.
- includes(:workout, :program, exercise_sets: [:exercise]).
- order(occurred_at: :desc)
- )
- end
-
- def new
- @workout = current_user.next_workout
- @training_session = current_user.next_training_session_for(@workout)
- end
-
- def create
- secure_params = params.require(:training_session).permit(:workout_id, :body_weight, exercise_sets_attributes: [
- :target_repetitions,
- :target_weight,
- :exercise_id
- ])
- workout = Workout.find(secure_params[:workout_id])
- training_session = current_user.begin_workout(
- workout,
- DateTime.now,
- secure_params[:body_weight]
- )
- training_session.update!(secure_params)
- redirect_to edit_training_session_path(training_session)
- end
-
- def edit
- @training_session = current_user.training_sessions.find(params[:id])
- end
-end
app/controllers/workouts_controller.rb
@@ -0,0 +1,30 @@
+class WorkoutsController < ApplicationController
+ def index
+ @workouts = paginate(
+ current_user.
+ workouts.
+ includes(:routine, :program, exercise_sets: [:exercise]).
+ order(occurred_at: :desc)
+ )
+ end
+
+ def new
+ @routine = current_user.next_routine
+ @workout = current_user.next_workout_for(@routine)
+ end
+
+ def create
+ secure_params = params.require(:workout).permit(:routine_id, :body_weight, exercise_sets_attributes: [
+ :target_repetitions,
+ :target_weight,
+ :exercise_id
+ ])
+ secure_params.merge!(occurred_at: DateTime.now)
+ workout = current_user.workouts.create!(secure_params)
+ redirect_to edit_workout_path(workout)
+ end
+
+ def edit
+ @workout = current_user.workouts.find(params[:id])
+ end
+end
app/models/csv/import.rb
@@ -23,18 +23,18 @@ class Csv::Import
def import(row)
workout_row = Csv::Workout.map_from(row, user)
- workout = program.workouts.find_by(name: workout_row.workout)
- training_session = user.begin_workout(
- workout,
+ routine = program.routines.find_by(name: workout_row.workout)
+ workout = user.begin_workout(
+ routine,
workout_row.date,
workout_row.body_weight_lb
)
- workout.exercises.each do |exercise|
+ routine.exercises.each do |exercise|
exercise_row = workout_row.find(exercise)
next if exercise_row.nil?
exercise_row.sets.compact.each_with_index do |completed_reps, index|
next if completed_reps.blank?
- training_session.train(
+ workout.train(
exercise,
exercise_row.weight_lb,
repetitions: completed_reps,
app/models/exercise_session.rb
@@ -1,16 +0,0 @@
-#class ExerciseSession < ActiveRecord::Base
- #belongs_to :training_session
- #belongs_to :exercise_workout
- #has_one :exercise, through: :exercise_workout
- #has_many :exercise_sets, dependent: :destroy
- #delegate :name, to: :exercise
- #accepts_nested_attributes_for :exercise_sets
-
- #def sets
- #exercise_sets
- #end
-
- #def to_sets
- #sets.map(&:actual_repetitions)
- #end
-#end
app/models/exercise_set.rb
@@ -1,4 +1,3 @@
class ExerciseSet < ActiveRecord::Base
- belongs_to :exercise_session
belongs_to :exercise
end
app/models/exercise_workout.rb
@@ -1,5 +0,0 @@
-class ExerciseWorkout < ActiveRecord::Base
- belongs_to :exercise
- belongs_to :workout
- delegate :name, to: :exercise
-end
app/models/program.rb
@@ -1,8 +1,8 @@
class Program < ActiveRecord::Base
STRONG_LIFTS = "StrongLifts 5×5"
- has_many :exercises, through: :workouts
- has_many :workouts
- has_many :exercise_workouts, through: :workouts
+ has_many :exercises, through: :routines
+ has_many :routines
+ has_many :recommendations, through: :routines
before_save do
self.slug = name.parameterize
@@ -18,8 +18,8 @@ class Program < ActiveRecord::Base
end
end
- def next_workout_after(workout)
- workouts.where.not(name: workout.name).first
+ def next_routine_after(routine)
+ routines.where.not(name: routine.name).first
end
def prepare_sets_for(user, exercise)
@@ -33,8 +33,7 @@ class Program < ActiveRecord::Base
end
def recommended_sets_for(user, exercise)
- recommended_sets = user.history_for(exercise).last_target_sets
- recommended_sets > 0 ? recommended_sets : recommendation_for(user, exercise).sets
+ recommendation_for(user, exercise).sets
end
def recommended_reps_for(user, exercise)
@@ -42,7 +41,7 @@ class Program < ActiveRecord::Base
end
def recommendation_for(user, exercise)
- exercise_workouts.find_by(exercise: exercise)
+ UserRecommendation.new(user, exercise, self)
end
class << self
app/models/progress.rb
@@ -1,9 +1,9 @@
class Progress
- attr_reader :exercise, :training_session
+ attr_reader :exercise, :workout
- def initialize(training_session, exercise)
+ def initialize(workout, exercise)
@exercise = exercise
- @training_session = training_session
+ @workout = workout
end
def to_sets
@@ -15,6 +15,6 @@ class Progress
end
def sets
- training_session.exercise_sets.where(exercise: exercise).order(:created_at)
+ workout.exercise_sets.where(exercise: exercise).order(:created_at)
end
end
app/models/quantity.rb
@@ -0,0 +1,26 @@
+class Quantity
+ attr_reader :amount, :unit
+
+ def initialize(amount, unit)
+ @amount = amount
+ @unit = unit
+ end
+
+ def to(target_unit)
+ # TODO:: convert amount to target unit
+ @amount
+ end
+
+ def to_f
+ @amount.to_f
+ end
+
+ def eql?(other)
+ converted = other.to(unit)
+ self.amount == converted
+ end
+
+ def to_s
+ to_f.to_s
+ end
+end
app/models/recommendation.rb
@@ -0,0 +1,5 @@
+class Recommendation < ActiveRecord::Base
+ belongs_to :exercise
+ belongs_to :routine
+ delegate :name, to: :exercise
+end
app/models/routine.rb
@@ -0,0 +1,35 @@
+class Routine < ActiveRecord::Base
+ belongs_to :program
+ has_many :recommendations
+ has_many :exercises, through: :recommendations
+
+ def slug
+ name.parameterize
+ end
+
+ def to_param
+ slug
+ end
+
+ def to_s
+ name
+ end
+
+ def add_exercise(exercise, sets: 5, repetitions: 5)
+ recommendations.create!(
+ exercise: exercise,
+ sets: sets,
+ repetitions: repetitions
+ ) unless exercises.include?(exercise)
+ end
+
+ def next_routine
+ program.next_routine_after(self)
+ end
+
+ def prepare_sets_for(user, workout)
+ exercises.each do |exercise|
+ workout.exercise_sets << program.prepare_sets_for(user, exercise)
+ end
+ end
+end
app/models/training_history.rb
@@ -8,31 +8,22 @@ class TrainingHistory
end
def personal_record
- user.exercise_sets.
- joins(:exercise).
- where(exercises: { id: exercise.id }).
- where('actual_repetitions = target_repetitions').
- maximum(:target_weight)
+ successful_sets.maximum(:target_weight)
end
def completed_any?
- user.exercise_sets.where(exercise: exercise).any?
+ sets.any?
end
def last_target_sets
- last_training_session = user.last_training_session(exercise)
- return 0 if last_training_session.blank?
- last_training_session.exercise_sets.where(exercise: exercise).count
+ last_workout = user.last_workout(exercise)
+ return 0 if last_workout.blank?
+ sets.where(workout: last_workout).count
end
def last_weight
- user.
- exercise_sets.
- joins(:exercise).
- where(exercises: { id: exercise.id }).
- where('actual_repetitions = target_repetitions').
- order('training_sessions.occurred_at').
- last.try(:target_weight).to_i
+ last_successful_set = successful_sets.order('workouts.occurred_at').last
+ last_successful_set.try(:target_weight).to_i
end
def next_weight
@@ -40,10 +31,20 @@ class TrainingHistory
end
def to_line_chart
- user.training_sessions.inject({}) do |memo, training_session|
- memo[training_session.occurred_at] =
- training_session.exercise_sets.where(exercise: exercise).maximum(:target_weight)
+ user.workouts.inject({}) do |memo, workout|
+ memo[workout.occurred_at] =
+ workout.exercise_sets.where(exercise: exercise).maximum(:target_weight)
memo
end
end
+
+ private
+
+ def sets
+ user.exercise_sets.where(exercise: exercise)
+ end
+
+ def successful_sets
+ sets.where('actual_repetitions = target_repetitions')
+ end
end
app/models/training_session.rb
@@ -1,30 +0,0 @@
-class TrainingSession < ActiveRecord::Base
- belongs_to :user
- belongs_to :workout
- has_one :program, through: :workout
- has_many :exercises, through: :exercise_sets
- has_many :exercise_sets, dependent: :destroy
- accepts_nested_attributes_for :exercise_sets
-
- def train(exercise, target_weight, repetitions:, set: nil)
- exercise_set =
- if set.present? && exercise_sets.where(exercise: exercise).at(set).present?
- exercise_sets.where(exercise: exercise).at(set)
- else
- exercise_sets.build(
- exercise: exercise,
- target_repetitions: program.recommended_reps_for(user, exercise)
- )
- end
- exercise_set.update!(actual_repetitions: repetitions, target_weight: target_weight)
- exercise_set
- end
-
- def progress_for(exercise)
- Progress.new(self, exercise)
- end
-
- def sets
- exercise_sets
- end
-end
app/models/user.rb
@@ -1,8 +1,8 @@
class User < ActiveRecord::Base
include Flippable
has_secure_password
- has_many :training_sessions
- has_many :exercise_sets, through: :training_sessions
+ has_many :workouts
+ has_many :exercise_sets, through: :workouts
has_many :user_sessions, dependent: :destroy
has_one :profile
has_many :received_emails
@@ -23,8 +23,8 @@ class User < ActiveRecord::Base
"Etc/UTC" == time_zone.name
end
- def first_training_session
- training_sessions.order(occurred_at: :asc).first
+ def first_workout
+ workouts.order(occurred_at: :asc).first
end
def gravatar_id
@@ -63,47 +63,51 @@ class User < ActiveRecord::Base
history_for(exercise).next_weight
end
- def begin_workout(workout, date, body_weight)
- matching_workouts = training_sessions.where(occurred_at: date)
+ def begin_workout(routine, date, body_weight)
+ matching_workouts = workouts.where(occurred_at: date)
if matching_workouts.any?
matching_workouts.first
else
- training_sessions.create!(
- workout: workout,
+ workouts.create!(
+ routine: routine,
occurred_at: date,
body_weight: body_weight.to_f
)
end
end
- def last_workout
- if training_sessions.any?
- training_sessions.order(:occurred_at).last.workout
+ def last_routine
+ if workouts.any?
+ last_workout.routine
else
- current_program.workouts.order(name: :desc).first
+ current_program.routines.order(name: :desc).first
end
end
- def next_workout
- last_workout.next_workout
+ def next_routine
+ last_routine.next_routine
end
- def next_training_session_for(workout = next_workout)
- last_body_weight = last_training_session.try(:body_weight)
- training_sessions.build(workout: workout, body_weight: last_body_weight).tap do |training_session|
- workout.prepare_sets_for(self, training_session)
+ def preferred_units
+ :lbs
+ end
+
+ def next_workout_for(routine = next_routine)
+ last_body_weight = last_workout.try(:body_weight)
+ workouts.build(routine: routine, body_weight: last_body_weight.to(preferred_units)).tap do |workout|
+ routine.prepare_sets_for(self, workout)
end
end
- def last_training_session(exercise = nil)
+ def last_workout(exercise = nil)
if exercise.present?
- training_sessions.
+ workouts.
joins(:exercises).
where(exercises: { id: exercise.id }).
order(:created_at).
last
else
- training_sessions.order(:created_at).last
+ workouts.order(:created_at).last
end
end
app/models/user_recommendation.rb
@@ -0,0 +1,24 @@
+class UserRecommendation
+ attr_reader :user, :exercise, :program
+
+ def initialize(user, exercise, program)
+ @user = user
+ @exercise = exercise
+ @program = program
+ end
+
+ def repetitions
+ recommendation.repetitions
+ end
+
+ def sets
+ recommended_sets = user.history_for(exercise).last_target_sets
+ recommended_sets > 0 ? recommended_sets : recommendation.sets
+ end
+
+ private
+
+ def recommendation
+ @recommendation ||= program.recommendations.find_by(exercise: exercise)
+ end
+end
app/models/workout.rb
@@ -1,35 +1,34 @@
class Workout < ActiveRecord::Base
- belongs_to :program
- has_many :exercise_workouts
- has_many :exercises, through: :exercise_workouts
+ belongs_to :user
+ belongs_to :routine
+ has_one :program, through: :routine
+ has_many :exercises, through: :exercise_sets
+ has_many :exercise_sets, dependent: :destroy
+ accepts_nested_attributes_for :exercise_sets
- def slug
- name.parameterize
+ def body_weight
+ Quantity.new(read_attribute(:body_weight), :lbs)
end
- def to_param
- slug
+ def train(exercise, target_weight, repetitions:, set: nil)
+ exercise_set =
+ if set.present? && exercise_sets.where(exercise: exercise).at(set).present?
+ exercise_sets.where(exercise: exercise).at(set)
+ else
+ exercise_sets.build(
+ exercise: exercise,
+ target_repetitions: program.recommended_reps_for(user, exercise)
+ )
+ end
+ exercise_set.update!(actual_repetitions: repetitions, target_weight: target_weight)
+ exercise_set
end
- def to_s
- name
+ def progress_for(exercise)
+ Progress.new(self, exercise)
end
- def add_exercise(exercise, sets: 5, repetitions: 5)
- exercise_workouts.create!(
- exercise: exercise,
- sets: sets,
- repetitions: repetitions
- ) unless exercises.include?(exercise)
- end
-
- def next_workout
- program.next_workout_after(self)
- end
-
- def prepare_sets_for(user, training_session)
- exercises.each do |exercise|
- training_session.exercise_sets << program.prepare_sets_for(user, exercise)
- end
+ def sets
+ exercise_sets
end
end
app/views/exercise_workouts/_exercise_workout.html.erb
@@ -1,2 +0,0 @@
-<%= render exercise_workout.exercise %>
-<p><%= exercise_workout.sets %> x <%= exercise_workout.repetitions %></p>
app/views/layouts/application.html.erb
@@ -32,7 +32,7 @@
<section class="top-bar-section">
<!-- Right Nav Section -->
<ul class="right">
- <% if feature_available?(:gym) %>
+ <% if feature_enabled?(:gym) %>
<li> <%= search_form %> </li>
<li class="divider"></li>
<li><%= link_to t(".gyms"), gyms_path %></li>
@@ -41,7 +41,7 @@
<li class="has-dropdown">
<a href="#"><%= gravatar_for(current_user, size: 16) %> <%= current_user.username %></a>
<ul class="dropdown">
- <li><%= link_to t(".nav.user.training_sessions"), training_sessions_path %></li>
+ <li><%= link_to t(".nav.user.workouts"), workouts_path %></li>
<li><%= link_to t(".nav.user.profile_edit"), edit_profile_path(current_user) %></li>
<li><%= link_to t(".nav.user.profile_view"), profile_path(current_user) %></li>
<li class="divider"></li>
app/views/profiles/show.html.erb
@@ -4,8 +4,8 @@
<%= gravatar_for(@user, size: 128) %>
<% end %>
<h1><%= link_to @user.username, profile_path(@user) %></h1>
- <% if @user.training_sessions.any? %>
- <p><%= t('.workouts_completed', count: @user.training_sessions.count, first_session: l(@user.training_sessions.order(occurred_at: :asc).first.occurred_at, format: :long)) %></p>
+ <% if @user.workouts.any? %>
+ <p><%= t('.workouts_completed', count: @user.workouts.count, first_session: l(@user.workouts.order(occurred_at: :asc).first.occurred_at, format: :long)) %></p>
<% else %>
<p><%= t('.no_workouts_completed') %></p>
<% end %>
app/views/programs/show.html.erb
@@ -1,6 +1,6 @@
<div class="small-12 columns">
<div class="row">
<h1><%= link_to @program.name, program_path(@program) %></h1>
- <%= render @program.workouts.includes(exercise_workouts: :exercise) %>
+ <%= render @program.routines.includes(recommendations: :exercise) %>
</div>
</div>
app/views/recommendations/_recommendation.html.erb
@@ -0,0 +1,2 @@
+<%= render recommendation.exercise %>
+<p><%= recommendation.sets %> x <%= recommendation.repetitions %></p>
app/views/routines/_routine.html.erb
@@ -0,0 +1,7 @@
+<div class="small-6 columns">
+ <div class="panel">
+ <%= link_to '', {}, name: routine.slug %>
+ <h1>routine <%= routine.name %>
+ <%= render routine.recommendations %>
+ </div>
+</div>
app/views/training_sessions/_edit.json.jbuilder
@@ -1,3 +0,0 @@
-json.training_session do
- json.partial! 'training_session', training_session: training_session
-end
app/views/training_sessions/_training_session.html.erb
@@ -1,13 +0,0 @@
-<tr>
- <td>
- <%= link_to training_session.workout, program_path(training_session.program, anchor: training_session.workout) %>
- </td>
- <td><%= I18n.l training_session.occurred_at, format: :short %></td>
- <td><%= training_session.body_weight %> lbs</td>
- <td>
- <% training_session.exercises.each do |exercise| %>
- <strong><%= exercise.name %></strong> @ <%= training_session.progress_for(exercise).max_weight %> lbs,
- <% end %>
- </td>
- <td> <%= link_to "edit", edit_training_session_path(training_session) %> </td>
-</tr>
app/views/training_sessions/edit.html.erb
@@ -1,17 +0,0 @@
-<div class="row">
- <div class="large-12 columns">
- <div id="training-session-view"></div>
- <%= link_to t(:back_html), training_sessions_path %>
- </div>
-</div>
-
-
-<script type="text/javascript" charset="utf-8">
-var json = <%= raw render partial: 'edit.json.jbuilder', locals: { training_session: @training_session } %>;
-window.currentView = new Stronglifters.TrainingSessionView({
- el: 'training-session-view',
- data: function() {
- return json;
- }
-})
-</script>
app/views/training_sessions/update.json.jbuilder
@@ -1,3 +0,0 @@
-json.training_session do
- json.partial! 'training_session', training_session: @training_session
-end
app/views/workouts/_edit.json.jbuilder
@@ -0,0 +1,3 @@
+json.workout do
+ json.partial! 'workout', workout: workout
+end
app/views/training_sessions/_import_address_modal.html.erb → app/views/workouts/_import_address_modal.html.erb
File renamed without changes
app/views/workouts/_workout.html.erb
@@ -1,7 +1,17 @@
-<div class="small-6 columns">
- <div class="panel">
- <%= link_to '', {}, name: workout.slug %>
- <h1>Workout <%= workout.name %>
- <%= render workout.exercise_workouts %>
- </div>
-</div>
+<tr>
+ <td>
+ <%= link_to workout.routine, program_path(workout.program, anchor: workout.routine) %>
+ </td>
+ <td><%= I18n.l workout.occurred_at, format: :short %></td>
+ <td><%= workout.body_weight.to(:lbs) %> lbs</td>
+ <td>
+ <% workout.exercises.order(:created_at).uniq.each do |exercise| %>
+ <strong><%= exercise.name %></strong> @ <%= workout.progress_for(exercise).max_weight %> lbs
+ <% end %>
+ </td>
+ <td>
+ <% if feature_enabled?(:csv_import) %>
+ <%= link_to "edit", edit_workout_path(workout) %>
+ <% end %>
+ </td>
+</tr>
app/views/training_sessions/_training_session.jbuilder → app/views/workouts/_workout.jbuilder
@@ -1,7 +1,7 @@
-json.id training_session.id
-json.body_weight training_session.body_weight
-json.workout_name training_session.workout.name
-json.exercises training_session.exercise_sets.order(:created_at).group_by(&:exercise) do |exercise, exercise_sets|
+json.id workout.id
+json.body_weight workout.body_weight
+json.routine_name workout.routine.name
+json.exercises workout.exercise_sets.order(:created_at).group_by(&:exercise) do |exercise, exercise_sets|
json.id exercise.id
json.name exercise.name
json.sets exercise_sets.sort_by(&:created_at) do |set|
app/views/workouts/edit.html.erb
@@ -0,0 +1,17 @@
+<div class="row">
+ <div class="large-12 columns">
+ <div id="workout-view"></div>
+ <%= link_to t(:back_html), workouts_path %>
+ </div>
+</div>
+
+
+<script type="text/javascript" charset="utf-8">
+var json = <%= raw render partial: 'edit.json.jbuilder', locals: { workout: @workout } %>;
+window.currentView = new Stronglifters.WorkoutView({
+ el: 'workout-view',
+ data: function() {
+ return json;
+ }
+})
+</script>
app/views/training_sessions/index.html.erb → app/views/workouts/index.html.erb
@@ -1,7 +1,7 @@
-<% if @training_sessions.any? %>
+<% if @workouts.any? %>
<div class="row">
<div class="large-12 columns">
- <% if feature_available?(:csv_import) %>
+ <% if feature_enabled?(:csv_import) %>
<p class="text-center"> <a href="#" data-reveal-id="sendToStrongLiftsModal"><%= User.human_attribute_name(:import_address) %></a> </p>
<% end %>
<table>
@@ -15,20 +15,20 @@
</tr>
</thead>
<tbody>
- <%= render @training_sessions %>
+ <%= render @workouts %>
</tbody>
</table>
</div>
</div>
<div class="row">
<div class="large-12 text-center columns">
- <%= paginate @training_sessions, remote: false %>
+ <%= paginate @workouts, remote: false %>
</div>
</div>
<% else %>
<div class="row">
<div class="large-12 columns">
- <% if feature_available?(:csv_import) %>
+ <% if feature_enabled?(:csv_import) %>
<p class="text-center"> <a href="#" data-reveal-id="sendToStrongLiftsModal"><%= User.human_attribute_name(:import_address) %></a> </p>
<% end %>
<%= random_video %>
app/views/training_sessions/new.html.erb → app/views/workouts/new.html.erb
@@ -1,11 +1,11 @@
<div class="row">
<div class="small-12 columns">
- <%= form_for @training_session do |f| %>
+ <%= form_for @workout do |f| %>
<fieldset>
- <legend><%= TrainingSession.human_attribute_name(:body_weight) %></legend>
+ <legend><%= Workout.human_attribute_name(:body_weight) %></legend>
<%= f.number_field :body_weight %>
</fieldset>
- <% @training_session.exercise_sets.group_by(&:exercise).each do |exercise, exercise_sets| %>
+ <% @workout.exercise_sets.group_by(&:exercise).each do |exercise, exercise_sets| %>
<fieldset>
<legend><%= exercise.name %></legend>
<% exercise_sets.each.with_index(1) do |set, index| %>
@@ -28,10 +28,10 @@
<% end %>
<% end %>
- <%= f.hidden_field :workout_id %>
+ <%= f.hidden_field :routine_id %>
</fieldset>
<% end %>
- <%= f.hidden_field :workout_id %>
+ <%= f.hidden_field :routine_id %>
<%= f.submit "Start", class: "button round right" %>
<% end %>
</div>
app/views/workouts/update.json.jbuilder
@@ -0,0 +1,3 @@
+json.workout do
+ json.partial! 'workout', workout: @workout
+end
config/initializers/extensions.rb
@@ -0,0 +1,17 @@
+class Fixnum
+ def lbs
+ to_f.lbs
+ end
+end
+
+class Float
+ def lbs
+ Quantity.new(self, :lbs)
+ end
+end
+
+class NilClass
+ def to(units)
+ 0.0.lbs.to(units)
+ end
+end
config/locales/en.yml
@@ -49,7 +49,7 @@ en:
loading: "Loading..."
nav:
user:
- training_sessions: "Training sessions"
+ workouts: "Workouts"
log_out: "Log out"
profile_edit: "Edit profile"
profile_view: "View profile"
@@ -92,7 +92,7 @@ en:
password: "Password"
login_button: "Login"
register_link: "Create an account"
- training_sessions:
+ workouts:
import_address_modal:
blurb: This is your custom email address for sending CSV exports from the <a href="http://stronglifts.com/apps/">StrongLifts 5x5 mobile application</a>.
copy: Copy
config/routes.rb
@@ -3,12 +3,12 @@ Rails.application.routes.draw do
resources :sessions, only: [:new, :create, :destroy]
resources :registrations, only: [:new, :create]
resources :exercise_sets, only: [:update]
- resources :training_sessions, only: [:index, :new, :create, :edit]
+ resources :workouts, only: [:index, :new, :create, :edit]
resources :programs, only: [:show]
resources :profiles, only: [:new, :create, :show, :edit, :update], constraints: { id: /[^\/]+/ }
resources :gyms, only: [:index, :show, :new, :create]
get "/u/:id" => "profiles#show", constraints: { id: /[^\/]+/ }
- get "/dashboard" => "training_sessions#index", as: :dashboard
+ get "/dashboard" => "workouts#index", as: :dashboard
get "/terms" => "static_pages#terms"
get "/stronglifts/export" => "static_pages#export"
db/migrate/20160611165543_migrate_to_exercise_sets.rb
@@ -1,13 +1,17 @@
class MigrateToExerciseSets < ActiveRecord::Migration
def up
- ExerciseSession.find_each do |exercise_session|
- target_reps = exercise_session.exercise_workout.repetitions
- exercise_session.actual_sets.each do |n|
- say "Creating set for: #{exercise_session.name}: set: #{n}"
- exercise_session.exercise_sets.create!(
+ execute("SELECT * FROM exercise_sessions").each do |exercise_session|
+ actual_sets = exercise_session["actual_sets"].gsub(/{/, '').gsub(/}/, '').split(',').map(&:to_i)
+ actual_sets.each do |n|
+ say "Creating set for: #{exercise_session["name"]}: set: #{n}"
+
+ workout_id = exercise_session["exercise_workout_id"]
+ target_reps = execute("SELECT repetitions FROM exercise_workouts where id = '#{workout_id}'").first["repetitions"].to_i
+ ExerciseSet.create!(
+ exercise_session_id: exercise_session["id"],
actual_repetitions: n,
target_repetitions: target_reps,
- target_weight: exercise_session.target_weight,
+ target_weight: exercise_session["target_weight"],
)
end
end
db/migrate/20160623202817_migrate_exercise_id_to_exercise_sets.rb
@@ -1,8 +1,17 @@
class MigrateExerciseIdToExerciseSets < ActiveRecord::Migration
def change
ExerciseSet.where(exercise_id: nil).find_each do |set|
- set.exercise = set.exercise_session.exercise
- set.save!
+ result = execute(
+ <<-SQL
+SELECT ew.exercise_id
+FROM exercise_sessions es
+INNER JOIN exercise_workouts ew on ew.id = es.exercise_workout_id
+WHERE es.id = '#{set.exercise_session_id}'
+ SQL
+ )
+ exercise_id = result.first["exercise_id"]
+ say "updating set: #{set.id} to exercise: #{exercise_id}"
+ set.update_column(:exercise_id, exercise_id)
end
end
end
db/migrate/20160623205309_migrate_training_session_id_to_exercise_sets.rb
@@ -1,8 +1,16 @@
class MigrateTrainingSessionIdToExerciseSets < ActiveRecord::Migration
def change
ExerciseSet.where(training_session_id: nil).find_each do |set|
- set.training_session_id = set.exercise_session.training_session.id
- set.save!
+ result = execute(
+ <<-SQL
+SELECT training_session_id
+FROM exercise_sessions
+WHERE id = '#{set.exercise_session_id}'
+ SQL
+ )
+ training_session_id = result.first["training_session_id"]
+ say "updating set: #{set.id} to training_session: #{training_session_id}"
+ set.update_column(:training_session_id, training_session_id)
end
end
end
db/migrate/20160624192245_rename_workouts_to_routines.rb
@@ -0,0 +1,7 @@
+class RenameWorkoutsToRoutines < ActiveRecord::Migration
+ def change
+ rename_table :workouts, :routines
+ rename_column :exercise_workouts, :workout_id, :routine_id
+ rename_column :training_sessions, :workout_id, :routine_id
+ end
+end
db/migrate/20160624195736_rename_training_session_to_workouts.rb
@@ -0,0 +1,6 @@
+class RenameTrainingSessionToWorkouts < ActiveRecord::Migration
+ def change
+ rename_table :training_sessions, :workouts
+ rename_column :exercise_sets, :training_session_id, :workout_id
+ end
+end
db/migrate/20160624205748_rename_exercise_workouts_to_recommendations.rb
@@ -0,0 +1,5 @@
+class RenameExerciseWorkoutsToRecommendations < ActiveRecord::Migration
+ def change
+ rename_table :exercise_workouts, :recommendations
+ end
+end
db/migrate/20160624210652_add_missing_indexes.rb
@@ -0,0 +1,10 @@
+class AddMissingIndexes < ActiveRecord::Migration
+ def change
+ add_index :exercise_sets, :exercise_id
+ add_index :exercise_sets, [:exercise_id, :workout_id]
+ add_index :routines, :program_id
+ add_index :workouts, :routine_id
+ add_index :users, :username
+ add_index :users, [:username, :email]
+ end
+end
db/schema.rb
@@ -11,30 +11,24 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20160624034644) do
+ActiveRecord::Schema.define(version: 20160624210652) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
enable_extension "uuid-ossp"
create_table "exercise_sets", id: :uuid, default: "uuid_generate_v4()", force: :cascade do |t|
- t.integer "target_repetitions", null: false
+ t.integer "target_repetitions", null: false
t.integer "actual_repetitions"
- t.float "target_weight", null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.uuid "exercise_id", null: false
- t.uuid "training_session_id"
+ t.float "target_weight", null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.uuid "exercise_id", null: false
+ t.uuid "workout_id"
end
- create_table "exercise_workouts", id: :uuid, default: "uuid_generate_v4()", force: :cascade do |t|
- t.uuid "exercise_id", null: false
- t.uuid "workout_id", null: false
- t.integer "sets", null: false
- t.integer "repetitions", null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- end
+ add_index "exercise_sets", ["exercise_id", "workout_id"], name: "index_exercise_sets_on_exercise_id_and_workout_id", using: :btree
+ add_index "exercise_sets", ["exercise_id"], name: "index_exercise_sets_on_exercise_id", using: :btree
create_table "exercises", id: :uuid, default: "uuid_generate_v4()", force: :cascade do |t|
t.string "name", null: false
@@ -101,16 +95,23 @@ ActiveRecord::Schema.define(version: 20160624034644) do
add_index "received_emails", ["user_id"], name: "index_received_emails_on_user_id", using: :btree
- create_table "training_sessions", id: :uuid, default: "uuid_generate_v4()", force: :cascade do |t|
- t.uuid "user_id", null: false
+ create_table "recommendations", id: :uuid, default: "uuid_generate_v4()", force: :cascade do |t|
+ t.uuid "exercise_id", null: false
+ t.uuid "routine_id", null: false
+ t.integer "sets", null: false
+ t.integer "repetitions", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
- t.uuid "workout_id", null: false
- t.datetime "occurred_at", null: false
- t.float "body_weight"
end
- add_index "training_sessions", ["user_id"], name: "index_training_sessions_on_user_id", using: :btree
+ create_table "routines", id: :uuid, default: "uuid_generate_v4()", force: :cascade do |t|
+ t.uuid "program_id", null: false
+ t.string "name", null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ end
+
+ add_index "routines", ["program_id"], name: "index_routines_on_program_id", using: :btree
create_table "user_sessions", id: :uuid, default: "uuid_generate_v4()", force: :cascade do |t|
t.uuid "user_id", null: false
@@ -132,13 +133,21 @@ ActiveRecord::Schema.define(version: 20160624034644) do
t.datetime "updated_at", null: false
end
+ add_index "users", ["username", "email"], name: "index_users_on_username_and_email", using: :btree
+ add_index "users", ["username"], name: "index_users_on_username", using: :btree
+
create_table "workouts", id: :uuid, default: "uuid_generate_v4()", force: :cascade do |t|
- t.uuid "program_id", null: false
- t.string "name", null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
+ t.uuid "user_id", null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.uuid "routine_id", null: false
+ t.datetime "occurred_at", null: false
+ t.float "body_weight"
end
+ add_index "workouts", ["routine_id"], name: "index_workouts_on_routine_id", using: :btree
+ add_index "workouts", ["user_id"], name: "index_workouts_on_user_id", using: :btree
+
add_foreign_key "profiles", "gyms"
add_foreign_key "received_emails", "users"
add_foreign_key "user_sessions", "users"
db/seeds.rb
@@ -9,13 +9,13 @@ deadlift = Exercise.find_or_create_by!(name: "Deadlift")
dips = Exercise.find_or_create_by!(name: "Dips")
chin_ups = Exercise.find_or_create_by!(name: "Chinups")
-workout_a = program.workouts.find_or_create_by(name: "A")
+workout_a = program.routines.find_or_create_by(name: "A")
workout_a.add_exercise(squat, sets: 5, repetitions: 5)
workout_a.add_exercise(bench_press, sets: 5, repetitions: 5)
workout_a.add_exercise(barbell_row, sets: 5, repetitions: 5)
workout_a.add_exercise(dips, sets: 3, repetitions: 5)
-workout_b = program.workouts.find_or_create_by(name: "B")
+workout_b = program.routines.find_or_create_by(name: "B")
workout_b.add_exercise(squat, sets: 5, repetitions: 5)
workout_b.add_exercise(overhead_press, sets: 5, repetitions: 5)
workout_b.add_exercise(deadlift, sets: 1, repetitions: 5)
spec/controllers/exercise_sets_controller_spec.rb
@@ -9,11 +9,11 @@ describe ExerciseSetsController do
describe "#update" do
include_context "stronglifts_program"
- let(:training_session) { user.next_training_session_for(workout_a) }
+ let(:workout) { user.next_workout_for(routine_a) }
it "records the exercise" do
- training_session.update!(occurred_at: DateTime.now, body_weight: 225)
- exercise_set = training_session.exercise_sets.first
+ workout.update!(occurred_at: DateTime.now, body_weight: 225)
+ exercise_set = workout.exercise_sets.first
xhr :patch, :update, id: exercise_set.id, exercise_set: {
actual_weight: 315,
spec/controllers/training_sessions_controller_spec.rb
@@ -1,83 +0,0 @@
-require "rails_helper"
-
-describe TrainingSessionsController do
- let(:user) { create(:user) }
-
- before :each do
- http_login(user)
- end
-
- describe "#index" do
- include_context "stronglifts_program"
- let!(:training_session_a) { create(:training_session, user: user, workout: workout_a) }
- let!(:training_session_b) { create(:training_session, user: user, workout: workout_b) }
-
- it "loads all my training sessions" do
- get :index
- expect(assigns(:training_sessions)).to match_array([training_session_a, training_session_b])
- end
- end
-
- describe "#new" do
- include_context "stronglifts_program"
-
- it "loads the next workout in the program" do
- create(:training_session, user: user, workout: workout_a)
-
- get :new
-
- expect(assigns(:workout)).to eql(workout_b)
- end
-
- it "loads the first workout in the program" do
- get :new
-
- expect(assigns(:workout)).to eql(workout_a)
- end
- end
-
- describe "#create" do
- include_context "stronglifts_program"
- let(:body_weight) { rand(250.0) }
-
- it "creates a new training session" do
- post :create, training_session: {
- workout_id: workout_b.id,
- body_weight: body_weight
- }
- expect(user.reload.training_sessions.count).to eql(1)
- expect(user.last_workout).to eql(workout_b)
- expect(user.training_sessions.last.body_weight).to eql(body_weight.to_f)
- expect(response).to redirect_to(edit_training_session_path(user.training_sessions.last))
- end
-
- it 'creates the training session with the selected exercises' do
- post :create, training_session: {
- workout_id: workout_b.id,
- body_weight: body_weight,
- exercise_sets_attributes: [{
- exercise_id: squat.id,
- target_repetitions: 5,
- target_weight: 200,
- }]
- }
-
- expect(user.reload.training_sessions.count).to eql(1)
- expect(user.last_workout).to eql(workout_b)
- training_session = user.training_sessions.last
- expect(training_session.body_weight).to eql(body_weight.to_f)
- expect(training_session.workout).to eql(workout_b)
- expect(training_session.exercise_sets.count).to eql(1)
- expect(response).to redirect_to(edit_training_session_path(user.training_sessions.last))
- end
- end
-
- describe "#edit" do
- let(:training_session) { create(:training_session, user: user) }
-
- it "loads the training session" do
- get :edit, id: training_session.id
- expect(assigns(:training_session)).to eql(training_session)
- end
- end
-end
spec/controllers/workouts_controller_spec.rb
@@ -0,0 +1,83 @@
+require "rails_helper"
+
+describe WorkoutsController do
+ let(:user) { create(:user) }
+
+ before :each do
+ http_login(user)
+ end
+
+ describe "#index" do
+ include_context "stronglifts_program"
+ let!(:workout_a) { create(:workout, user: user, routine: routine_a) }
+ let!(:workout_b) { create(:workout, user: user, routine: routine_b) }
+
+ it "loads all my workouts" do
+ get :index
+ expect(assigns(:workouts)).to match_array([workout_a, workout_b])
+ end
+ end
+
+ describe "#new" do
+ include_context "stronglifts_program"
+
+ it "loads the next routine in the program" do
+ create(:workout, user: user, routine: routine_a)
+
+ get :new
+
+ expect(assigns(:routine)).to eql(routine_b)
+ end
+
+ it "loads the first routine in the program" do
+ get :new
+
+ expect(assigns(:routine)).to eql(routine_a)
+ end
+ end
+
+ describe "#create" do
+ include_context "stronglifts_program"
+ let(:body_weight) { rand(250.0).lbs }
+
+ it "creates a new workout" do
+ post :create, workout: {
+ routine_id: routine_b.id,
+ body_weight: body_weight
+ }
+ expect(user.reload.workouts.count).to eql(1)
+ expect(user.last_routine).to eql(routine_b)
+ expect(user.workouts.last.body_weight).to eql(body_weight)
+ expect(response).to redirect_to(edit_workout_path(user.workouts.last))
+ end
+
+ it 'creates the workout with the selected exercises' do
+ post :create, workout: {
+ routine_id: routine_b.id,
+ body_weight: body_weight,
+ exercise_sets_attributes: [{
+ exercise_id: squat.id,
+ target_repetitions: 5,
+ target_weight: 200,
+ }]
+ }
+
+ expect(user.reload.workouts.count).to eql(1)
+ expect(user.last_routine).to eql(routine_b)
+ workout = user.workouts.last
+ expect(workout.body_weight).to eql(body_weight)
+ expect(workout.routine).to eql(routine_b)
+ expect(workout.exercise_sets.count).to eql(1)
+ expect(response).to redirect_to(edit_workout_path(user.workouts.last))
+ end
+ end
+
+ describe "#edit" do
+ let(:workout) { create(:workout, user: user) }
+
+ it "loads the workouts" do
+ get :edit, id: workout.id
+ expect(assigns(:workout)).to eql(workout)
+ end
+ end
+end
spec/features/profiles_spec.rb
@@ -9,7 +9,7 @@ feature "Profiles", type: :feature do
page.set_rack_session(user_id: user_session.id)
end
- context "when the user has not completed any workouts" do
+ context "when the user has not completed any routines" do
subject { ProfilePage.new(user) }
before { subject.visit_page }
@@ -18,7 +18,7 @@ feature "Profiles", type: :feature do
expect(page).to have_content(user.username)
end
- it "displays the number of workouts completed" do
+ it "displays the number of routines completed" do
translations = I18n.translate("profiles.show.no_workouts_completed")
expect(page).to have_content(translations)
end
spec/features/training_sessions_spec.rb → spec/features/workouts_spec.rb
@@ -1,10 +1,10 @@
require "rails_helper"
-feature "Training Sessions", type: :feature do
+feature "Workouts", type: :feature do
include_context "stronglifts_program"
- subject { TrainingSessionsPage.new }
+ subject { WorkoutsPage.new }
let(:user) { create(:user, password: "password") }
- let!(:training_session) { create(:training_session, user: user, workout: workout_a, occurred_at: DateTime.now, body_weight: 210.0) }
+ let!(:workout) { create(:workout, user: user, routine: routine_a, occurred_at: DateTime.now, body_weight: 210.0) }
before :each do
subject.login_with(user.username, "password")
@@ -13,7 +13,7 @@ feature "Training Sessions", type: :feature do
describe "view training history" do
it "displays each training session" do
- expect(page).to have_content(training_session.occurred_at.strftime("%a, %d %b"))
+ expect(page).to have_content(workout.occurred_at.strftime("%a, %d %b"))
end
end
end
spec/javascripts/views/training_session_view_spec.js.coffee
@@ -1,15 +1,15 @@
-#= require views/training_session_view
-describe "TrainingSessionView", ->
+#= require views/workout_view
+describe "WorkoutView", ->
beforeEach ->
@el = $('<div>')
- @subject = new Stronglifters.TrainingSessionView(
+ @subject = new Stronglifters.WorkoutView(
el: @el,
data: ->
{
- training_session:
+ workout:
id: "1",
body_weight: 225,
- workout_name: "A",
+ routine_name: "A",
exercises: [{
name: 'Squat',
sets: 3,
@@ -21,35 +21,35 @@ describe "TrainingSessionView", ->
)
it "has one exercise", ->
- @subject.get('training_session.exercises')
- expect(@subject.get('training_session.exercises').length).toEqual(1)
+ @subject.get('workout.exercises')
+ expect(@subject.get('workout.exercises').length).toEqual(1)
it "indicates no progress recorded", ->
- result = @subject.get('training_session.exercises.0.reps.0.status')
+ result = @subject.get('workout.exercises.0.reps.0.status')
expect(result).toEqual('secondary')
describe "updating progress", ->
describe "when no reps are completed", ->
it "sets the reps to the target", ->
@el.find('button').first().trigger('click')
- result = @subject.get('training_session.exercises.0.reps.0.completed')
+ result = @subject.get('workout.exercises.0.reps.0.completed')
expect(result).toEqual(5)
it "indicates a successful set", ->
@el.find('button').first().trigger('click')
- result = @subject.get('training_session.exercises.0.reps.0.status')
+ result = @subject.get('workout.exercises.0.reps.0.status')
expect(result).toEqual('success')
describe "when at least one rep is completed", ->
beforeEach ->
- @subject.set('training_session.exercises.0.reps.0.completed', 5)
+ @subject.set('workout.exercises.0.reps.0.completed', 5)
it 'decrements the count', ->
@el.find('button').first().trigger('click')
- result = @subject.get('training_session.exercises.0.reps.0.completed')
+ result = @subject.get('workout.exercises.0.reps.0.completed')
expect(result).toEqual(4)
it "indicates a failed set", ->
@el.find('button').first().trigger('click')
- result = @subject.get('training_session.exercises.0.reps.0.status')
+ result = @subject.get('workout.exercises.0.reps.0.status')
expect(result).toEqual('alert')
spec/jobs/upload_stronglifts_backup_job_spec.rb
@@ -13,7 +13,7 @@ describe UploadStrongliftsBackupJob, type: :job do
it "adds each workout to the list of training sessions for the user" do
subject.perform(user, backup_file, program)
- expect(user.training_sessions.count).to eql(168)
+ expect(user.workouts.count).to eql(168)
end
end
spec/models/csv/import_spec.rb
@@ -42,23 +42,23 @@ describe Csv::Import do
it "imports each training session" do
subject.import_from(directory)
- training_session = user.training_sessions.order(:occurred_at).first
+ workout = user.workouts.order(:occurred_at).first
expected_date = user.time_zone.local_to_utc(Time.utc(2015, 03, 02))
- expect(training_session.occurred_at).to eql(expected_date)
- expect(training_session.workout).to eql(workout_a)
- expect(training_session.body_weight).to eql(205.0)
- expect(training_session.exercise_sets.count).to eql(15)
+ expect(workout.occurred_at).to eql(expected_date)
+ expect(workout.routine).to eql(routine_a)
+ expect(workout.body_weight).to eql(205.0.lbs)
+ expect(workout.exercise_sets.count).to eql(15)
expect(
- training_session.exercise_sets.map { |x| x.exercise.name }.uniq
+ workout.exercise_sets.map { |x| x.exercise.name }.uniq
).to match_array(["Squat", "Bench Press", "Barbell Row"])
end
it "imports the completed squat exercise" do
subject.import_from(directory)
- training_session = user.training_sessions.order(:occurred_at).first
- squat_session = training_session.progress_for(squat)
+ workout = user.workouts.order(:occurred_at).first
+ squat_session = workout.progress_for(squat)
expect(squat_session.to_sets).to eql([5, 5, 5, 5, 5])
end
@@ -66,8 +66,8 @@ describe Csv::Import do
it "imports the completed bench exercise" do
subject.import_from(directory)
- training_session = user.training_sessions.order(:occurred_at).first
- bench_session = training_session.progress_for(bench_press)
+ workout = user.workouts.order(:occurred_at).first
+ bench_session = workout.progress_for(bench_press)
expect(bench_session.sets.count).to eql(5)
expect(bench_session.to_sets).to eql([5, 5, 5, 5, 5])
end
@@ -75,8 +75,8 @@ describe Csv::Import do
it "imports the completed barbell row exercise" do
subject.import_from(directory)
- training_session = user.training_sessions.order(:occurred_at).first
- row_session = training_session.progress_for(barbell_row)
+ workout = user.workouts.order(:occurred_at).first
+ row_session = workout.progress_for(barbell_row)
expect(row_session.to_sets).to eql([5, 5, 5, 5, 5])
expect(row_session.sets.at(0).target_weight).to eql(65.0)
expect(row_session.sets.at(0).actual_repetitions).to eql(5)
@@ -93,7 +93,7 @@ describe Csv::Import do
it "excludes items that have already been imported" do
subject.import_from(directory)
subject.import_from(directory)
- expect(user.training_sessions.count).to eql(168)
+ expect(user.workouts.count).to eql(168)
end
end
@@ -102,8 +102,8 @@ describe Csv::Import do
row = ["06/11/15", "", "A", "97.4", "215", "Squat", "120", "265", "5", "5", "5", nil, nil, "Bench press", "77.5", "170", "5", "5", "5", "5", "5", "Barbell row", "67.5", "150", "5", "5", "5", "5", "5", "Dips", "5", "12.5", "5", "5", "5"]
subject.import(row)
- training_session = user.training_sessions.first
- progress = training_session.progress_for(dips)
+ workout = user.workouts.first
+ progress = workout.progress_for(dips)
expect(progress).to_not be_nil
expect(progress.to_sets).to eql([5, 5, 5])
end
@@ -112,8 +112,8 @@ describe Csv::Import do
row = ["14/03/15", "", "B", "92.87", "205", "Squat", "37.5", "85", "5", "5", "5", "5", "5", "Overhead press", "32.5", "70", "5", "5", "5", "5", "5", "Deadlift", "52.5", "115", "5", nil, nil, nil, nil, "Chinups", "0", "0", "5", "3", "2"]
subject.import(row)
- training_session = user.training_sessions.first
- progress = training_session.progress_for(chinups)
+ workout = user.workouts.first
+ progress = workout.progress_for(chinups)
expect(progress).to_not be_nil
expect(progress.to_sets).to eql([5, 3, 2])
expect(progress.sets.at(0).target_weight).to eql(0.0)
@@ -131,12 +131,12 @@ describe Csv::Import do
row = ["06/05/16", "", "B", "101.93", "225", "Squat", "125", "275", "5", "5", "5", "", "", "Overhead press", "57.5", "125", "5", "5", "5", "5", "5", "Deadlift", "127.5", "285", "5", "", "", "" , "", "", "", "", "", ""]
subject.import(row)
- training_session = user.training_sessions.first
- expect(training_session.progress_for(squat).sets.count).to eql(3)
- expect(training_session.progress_for(squat).to_sets).to eql([5, 5, 5])
+ workout = user.workouts.first
+ expect(workout.progress_for(squat).sets.count).to eql(3)
+ expect(workout.progress_for(squat).to_sets).to eql([5, 5, 5])
- expect(training_session.progress_for(deadlift).sets.count).to eql(1)
- expect(training_session.progress_for(deadlift).to_sets).to eql([5])
+ expect(workout.progress_for(deadlift).sets.count).to eql(1)
+ expect(workout.progress_for(deadlift).to_sets).to eql([5])
end
end
end
spec/models/routine_spec.rb
@@ -0,0 +1,37 @@
+require "rails_helper"
+
+describe Routine do
+ subject { build(:routine) }
+
+ describe "#add_exercise" do
+ let(:exercise) { create(:exercise) }
+
+ before :each do
+ subject.save!
+ end
+
+ it "adds a new exercise with the specified sets" do
+ sets = rand(10)
+ subject.add_exercise(exercise, sets: sets)
+ expect(subject.recommendations.first.sets).to eql(sets)
+ end
+
+ it "adds the new exercise with the specified reps" do
+ repetitions = rand(10)
+ subject.add_exercise(exercise, repetitions: repetitions)
+ expect(subject.recommendations.first.repetitions).to eql(repetitions)
+ end
+
+ it "adds the excercise" do
+ subject.add_exercise(exercise)
+ expect(subject.recommendations.first.exercise).to eql(exercise)
+ end
+
+ it "does not add a duplicate exercise" do
+ subject.add_exercise(exercise)
+ subject.add_exercise(exercise)
+ expect(subject.exercises.count).to eql(1)
+ expect(subject.recommendations.count).to eql(1)
+ end
+ end
+end
spec/models/training_history_spec.rb
@@ -11,7 +11,7 @@ describe TrainingHistory do
let(:body_weight) { 210 }
before :each do
- session = user.begin_workout(workout_a, date, body_weight)
+ session = user.begin_workout(routine_a, date, body_weight)
5.times do
session.train(squat, target_weight, repetitions: 5)
session.train(bench_press, target_weight + 10, repetitions: 5)
@@ -36,7 +36,7 @@ describe TrainingHistory do
describe "when the exercise has been performed at least once" do
it "returns true" do
- session = user.begin_workout(workout_a, DateTime.now, 225)
+ session = user.begin_workout(routine_a, DateTime.now, 225)
3.times do
session.train(squat, 310, repetitions: 5)
end
spec/models/training_session_spec.rb
@@ -1,97 +0,0 @@
-require "rails_helper"
-
-describe TrainingSession, type: :model do
- subject { create(:training_session) }
-
- describe "#train" do
- let(:workout) { subject.workout }
- let(:target_weight) { 200 }
- let(:squat) { create(:exercise) }
-
- before :each do
- workout.add_exercise(squat)
- end
-
- it "returns a completed exercise" do
- result = subject.train(squat, target_weight, repetitions: 5)
-
- expect(result).to be_persisted
- expect(result.exercise).to eql(squat)
- expect(subject.progress_for(squat).to_sets).to eql([5])
- expect(subject.sets.at(0).exercise).to eql(squat)
- expect(subject.sets.at(0).target_weight).to eql(target_weight.to_f)
- expect(subject.sets.at(0).target_repetitions).to eql(5)
- expect(subject.sets.at(0).actual_repetitions).to eql(5)
- end
-
- it 'records the next set' do
- subject.train(squat, target_weight, repetitions: 5)
- result = subject.train(squat, target_weight, repetitions: 3)
-
- expect(result).to be_persisted
- expect(result.exercise).to eql(squat)
- expect(subject.progress_for(squat).to_sets).to eql([5, 3])
- expect(subject.sets.at(0).exercise).to eql(squat)
- expect(subject.sets.at(0).target_weight).to eql(target_weight.to_f)
- expect(subject.sets.at(0).target_repetitions).to eql(5)
- expect(subject.sets.at(0).actual_repetitions).to eql(5)
- expect(subject.sets.at(1).exercise).to eql(squat)
- expect(subject.sets.at(1).target_weight).to eql(target_weight.to_f)
- expect(subject.sets.at(1).target_repetitions).to eql(5)
- expect(subject.sets.at(1).actual_repetitions).to eql(3)
- end
-
- it "updates a completed exercise" do
- subject.train(squat, target_weight, repetitions: 5)
- subject.train(squat, target_weight, repetitions: 5)
- subject.train(squat, target_weight, repetitions: 5)
-
- new_weight = target_weight + 10
- result = subject.train(squat, new_weight, repetitions: 3, set: 1)
-
- expect(result).to be_persisted
- expect(result.exercise).to eql(squat)
- progress = subject.progress_for(squat)
- expect(progress.to_sets).to eql([5, 3, 5])
- expect(progress.sets.at(0).exercise).to eql(squat)
- expect(progress.sets.at(0).target_weight).to eql(target_weight.to_f)
- expect(progress.sets.at(0).target_repetitions).to eql(5)
- expect(progress.sets.at(0).actual_repetitions).to eql(5)
- expect(progress.sets.at(1).exercise).to eql(squat)
- expect(progress.sets.at(1).target_weight).to eql(new_weight.to_f)
- expect(progress.sets.at(1).target_repetitions).to eql(5)
- expect(progress.sets.at(1).actual_repetitions).to eql(3)
- expect(progress.sets.at(2).exercise).to eql(squat)
- expect(progress.sets.at(2).target_weight).to eql(target_weight.to_f)
- expect(progress.sets.at(2).target_repetitions).to eql(5)
- expect(progress.sets.at(2).actual_repetitions).to eql(5)
- end
-
- it "cannot save a duplicate exercise" do
- subject.train(squat, target_weight, repetitions: 5, set: 0)
- subject.train(squat, target_weight, repetitions: 5, set: 0)
-
- expect(subject.exercise_sets.count).to eql(1)
- end
- end
-
- describe "#progress_for" do
- let(:exercise) { create(:exercise) }
- let(:other_exercise) { create(:exercise) }
- let(:workout) { subject.workout }
-
- before :each do
- workout.add_exercise(exercise)
- workout.add_exercise(other_exercise)
- subject.train(exercise, 100, repetitions: 5)
- subject.train(other_exercise, 100, repetitions: 5)
- subject.train(exercise, 100, repetitions: 5)
- end
-
- it "returns the progress for the specific exercise" do
- result = subject.progress_for(exercise)
- expect(result.exercise).to eql(exercise)
- expect(result.to_sets).to eql([5, 5])
- end
- end
-end
spec/models/user_spec.rb
@@ -110,19 +110,19 @@ describe User do
describe "#personal_record_for" do
include_context "stronglifts_program"
let(:user) { create(:user) }
- let(:exercise_workout) { workout_a.exercise_workouts.first }
- let(:exercise) { exercise_workout.exercise }
+ let(:recommendation) { routine_a.recommendations.first }
+ let(:exercise) { recommendation.exercise }
before :each do
- training_session = user.training_sessions.create!(
- workout: workout_a,
+ workout = user.workouts.create!(
+ routine: routine_a,
occurred_at: DateTime.now.utc
)
- training_session.train(squat, 201, repetitions: exercise_workout.repetitions)
- training_session.train(squat, 202, repetitions: exercise_workout.repetitions)
- training_session.train(squat, 210, repetitions: exercise_workout.repetitions - 1)
- training_session.train(squat, 204, repetitions: exercise_workout.repetitions)
- training_session.train(squat, 205, repetitions: exercise_workout.repetitions)
+ workout.train(squat, 201, repetitions: recommendation.repetitions)
+ workout.train(squat, 202, repetitions: recommendation.repetitions)
+ workout.train(squat, 210, repetitions: recommendation.repetitions - 1)
+ workout.train(squat, 204, repetitions: recommendation.repetitions)
+ workout.train(squat, 205, repetitions: recommendation.repetitions)
end
it "returns the users maximum amount of weight lifted" do
@@ -132,27 +132,27 @@ describe User do
describe "#begin_workout" do
subject { create(:user) }
- let(:workout) { create(:workout) }
+ let(:routine) { create(:routine) }
let(:today) { DateTime.now }
it "creates a new training session" do
- result = subject.begin_workout(workout, today, 200)
+ result = subject.begin_workout(routine, today, 200)
expect(result).to be_persisted
- expect(subject.training_sessions.count).to eql(1)
- expect(subject.training_sessions.first).to eql(result)
- expect(result.workout).to eql(workout)
+ expect(subject.workouts.count).to eql(1)
+ expect(subject.workouts.first).to eql(result)
+ expect(result.routine).to eql(routine)
expect(result.occurred_at).to eql(today.utc)
- expect(result.body_weight).to eql(200.0)
+ expect(result.body_weight).to eql(200.lbs)
end
it "returns the existing workout for that day" do
- result = subject.begin_workout(workout, today, 200)
- expect(subject.begin_workout(workout, today, 200)).to eql(result)
+ result = subject.begin_workout(routine, today, 200)
+ expect(subject.begin_workout(routine, today, 200)).to eql(result)
end
it "returns different sessions for different days" do
- todays_result = subject.begin_workout(workout, today, 200)
- tomorrows_result = subject.begin_workout(workout, DateTime.tomorrow, 200)
+ todays_result = subject.begin_workout(routine, today, 200)
+ tomorrows_result = subject.begin_workout(routine, DateTime.tomorrow, 200)
expect(todays_result).to_not eql(tomorrows_result)
end
end
@@ -162,16 +162,16 @@ describe User do
subject { create(:user) }
it "removes all the associations" do
- training_session = subject.begin_workout(workout_a, Date.today, 200)
- training_session.train(squat, 200, repetitions: 5)
- training_session.train(squat, 200, repetitions: 5)
- training_session.train(squat, 200, repetitions: 5)
- training_session.train(squat, 200, repetitions: 5)
- training_session.train(squat, 200, repetitions: 5)
+ workout = subject.begin_workout(routine_a, Date.today, 200)
+ workout.train(squat, 200, repetitions: 5)
+ workout.train(squat, 200, repetitions: 5)
+ workout.train(squat, 200, repetitions: 5)
+ workout.train(squat, 200, repetitions: 5)
+ workout.train(squat, 200, repetitions: 5)
- subject.training_sessions.destroy_all
+ subject.workouts.destroy_all
- expect(TrainingSession.all).to be_empty
+ expect(Workout.all).to be_empty
expect(ExerciseSet.all).to be_empty
end
end
spec/models/workout_spec.rb
@@ -1,37 +1,97 @@
require "rails_helper"
-describe Workout do
- subject { build(:workout) }
+describe Workout, type: :model do
+ subject { create(:workout) }
- describe "#add_exercise" do
- let(:exercise) { create(:exercise) }
+ describe "#train" do
+ let(:routine) { subject.routine }
+ let(:target_weight) { 200 }
+ let(:squat) { create(:exercise) }
before :each do
- subject.save!
+ routine.add_exercise(squat)
+ end
+
+ it "returns a completed exercise" do
+ result = subject.train(squat, target_weight, repetitions: 5)
+
+ expect(result).to be_persisted
+ expect(result.exercise).to eql(squat)
+ expect(subject.progress_for(squat).to_sets).to eql([5])
+ expect(subject.sets.at(0).exercise).to eql(squat)
+ expect(subject.sets.at(0).target_weight).to eql(target_weight.to_f)
+ expect(subject.sets.at(0).target_repetitions).to eql(5)
+ expect(subject.sets.at(0).actual_repetitions).to eql(5)
+ end
+
+ it 'records the next set' do
+ subject.train(squat, target_weight, repetitions: 5)
+ result = subject.train(squat, target_weight, repetitions: 3)
+
+ expect(result).to be_persisted
+ expect(result.exercise).to eql(squat)
+ expect(subject.progress_for(squat).to_sets).to eql([5, 3])
+ expect(subject.sets.at(0).exercise).to eql(squat)
+ expect(subject.sets.at(0).target_weight).to eql(target_weight.to_f)
+ expect(subject.sets.at(0).target_repetitions).to eql(5)
+ expect(subject.sets.at(0).actual_repetitions).to eql(5)
+ expect(subject.sets.at(1).exercise).to eql(squat)
+ expect(subject.sets.at(1).target_weight).to eql(target_weight.to_f)
+ expect(subject.sets.at(1).target_repetitions).to eql(5)
+ expect(subject.sets.at(1).actual_repetitions).to eql(3)
end
- it "adds a new exercise with the specified sets" do
- sets = rand(10)
- subject.add_exercise(exercise, sets: sets)
- expect(subject.exercise_workouts.first.sets).to eql(sets)
+ it "updates a completed exercise" do
+ subject.train(squat, target_weight, repetitions: 5)
+ subject.train(squat, target_weight, repetitions: 5)
+ subject.train(squat, target_weight, repetitions: 5)
+
+ new_weight = target_weight + 10
+ result = subject.train(squat, new_weight, repetitions: 3, set: 1)
+
+ expect(result).to be_persisted
+ expect(result.exercise).to eql(squat)
+ progress = subject.progress_for(squat)
+ expect(progress.to_sets).to eql([5, 3, 5])
+ expect(progress.sets.at(0).exercise).to eql(squat)
+ expect(progress.sets.at(0).target_weight).to eql(target_weight.to_f)
+ expect(progress.sets.at(0).target_repetitions).to eql(5)
+ expect(progress.sets.at(0).actual_repetitions).to eql(5)
+ expect(progress.sets.at(1).exercise).to eql(squat)
+ expect(progress.sets.at(1).target_weight).to eql(new_weight.to_f)
+ expect(progress.sets.at(1).target_repetitions).to eql(5)
+ expect(progress.sets.at(1).actual_repetitions).to eql(3)
+ expect(progress.sets.at(2).exercise).to eql(squat)
+ expect(progress.sets.at(2).target_weight).to eql(target_weight.to_f)
+ expect(progress.sets.at(2).target_repetitions).to eql(5)
+ expect(progress.sets.at(2).actual_repetitions).to eql(5)
end
- it "adds the new exercise with the specified reps" do
- repetitions = rand(10)
- subject.add_exercise(exercise, repetitions: repetitions)
- expect(subject.exercise_workouts.first.repetitions).to eql(repetitions)
+ it "cannot save a duplicate exercise" do
+ subject.train(squat, target_weight, repetitions: 5, set: 0)
+ subject.train(squat, target_weight, repetitions: 5, set: 0)
+
+ expect(subject.exercise_sets.count).to eql(1)
end
+ end
- it "adds the excercise" do
- subject.add_exercise(exercise)
- expect(subject.exercise_workouts.first.exercise).to eql(exercise)
+ describe "#progress_for" do
+ let(:exercise) { create(:exercise) }
+ let(:other_exercise) { create(:exercise) }
+ let(:routine) { subject.routine }
+
+ before :each do
+ routine.add_exercise(exercise)
+ routine.add_exercise(other_exercise)
+ subject.train(exercise, 100, repetitions: 5)
+ subject.train(other_exercise, 100, repetitions: 5)
+ subject.train(exercise, 100, repetitions: 5)
end
- it "does not add a duplicate exercise" do
- subject.add_exercise(exercise)
- subject.add_exercise(exercise)
- expect(subject.exercises.count).to eql(1)
- expect(subject.exercise_workouts.count).to eql(1)
+ it "returns the progress for the specific exercise" do
+ result = subject.progress_for(exercise)
+ expect(result.exercise).to eql(exercise)
+ expect(result.to_sets).to eql([5, 5])
end
end
end
spec/routing/dashboard_routing_spec.rb
@@ -2,6 +2,6 @@ require "rails_helper"
describe "/dashboard", type: :routing do
it "routes to the items listing" do
- expect(get: "/dashboard").to route_to("training_sessions#index")
+ expect(get: "/dashboard").to route_to("workouts#index")
end
end
spec/support/pages/training_sessions_page.rb
@@ -1,7 +0,0 @@
-require_relative "../page_model.rb"
-
-class TrainingSessionsPage < PageModel
- def initialize
- super training_sessions_path
- end
-end
spec/support/pages/workouts_page.rb
@@ -0,0 +1,7 @@
+require_relative "../page_model.rb"
+
+class WorkoutsPage < PageModel
+ def initialize
+ super workouts_path
+ end
+end
spec/support/stronglifts_program.rb
@@ -2,23 +2,23 @@ shared_context "stronglifts_program" do
let!(:program) { create(:program, name: "StrongLifts 5×5") }
let!(:squat) { create(:exercise, name: "Squat") }
- let!(:workout_a) { program.workouts.create name: "A" }
+ let!(:routine_a) { program.routines.create name: "A" }
let!(:bench_press) { create(:exercise, name: "Bench Press") }
let!(:barbell_row) { create(:exercise, name: "Barbell Row") }
let!(:dips) { create(:exercise, name: "Dips") }
- let!(:squat_workout) { workout_a.add_exercise(squat, sets: 5, repetitions: 5) }
- let!(:bench_workout) { workout_a.add_exercise(bench_press, sets: 5, repetitions: 5) }
- let!(:row_workout) { workout_a.add_exercise(barbell_row, sets: 5, repetitions: 5) }
- let!(:dips_workout) { workout_a.add_exercise(dips, sets: 3, repetitions: 5) }
+ let!(:squat_workout) { routine_a.add_exercise(squat, sets: 5, repetitions: 5) }
+ let!(:bench_workout) { routine_a.add_exercise(bench_press, sets: 5, repetitions: 5) }
+ let!(:row_workout) { routine_a.add_exercise(barbell_row, sets: 5, repetitions: 5) }
+ let!(:dips_workout) { routine_a.add_exercise(dips, sets: 3, repetitions: 5) }
- let!(:workout_b) { program.workouts.create name: "B" }
+ let!(:routine_b) { program.routines.create name: "B" }
let!(:overhead_press) { create(:exercise, name: "Overhead Press") }
let!(:deadlift) { create(:exercise, name: "Deadlift") }
let!(:chinups) { create(:exercise, name: "Chinups") }
- let!(:squat_workout_b) { workout_b.add_exercise(squat, sets: 5, repetitions: 5) }
- let!(:overhead_press_workout) { workout_b.add_exercise(overhead_press, sets: 5, repetitions: 5) }
- let!(:deadlift_workout) { workout_b.add_exercise(deadlift, sets: 1, repetitions: 5) }
+ let!(:squat_workout_b) { routine_b.add_exercise(squat, sets: 5, repetitions: 5) }
+ let!(:overhead_press_workout) { routine_b.add_exercise(overhead_press, sets: 5, repetitions: 5) }
+ let!(:deadlift_workout) { routine_b.add_exercise(deadlift, sets: 1, repetitions: 5) }
let!(:chinups_workout) do
- workout_b.add_exercise(chinups, sets: 3, repetitions: 5)
+ routine_b.add_exercise(chinups, sets: 3, repetitions: 5)
end
end
spec/factories.rb
@@ -5,9 +5,9 @@ FactoryGirl.define do
factory :program do
name { FFaker::Internet.user_name }
end
- factory :training_session do
+ factory :workout do
association :user
- association :workout
+ association :routine
occurred_at { DateTime.now }
body_weight { rand(250) }
end
@@ -18,7 +18,7 @@ FactoryGirl.define do
password_confirmation "password"
terms_and_conditions "1"
end
- factory :workout do
+ factory :routine do
association :program
name { FFaker::Internet.user_name }
end
spec/rails_helper.rb
@@ -7,12 +7,12 @@ CodeClimate::TestReporter.start
require "spec_helper"
require File.expand_path("../../config/environment", __FILE__)
require "rspec/rails"
+# Add additional requires below this line. Rails is not loaded until this point!
require "capybara/poltergeist"
require "rack_session_access/capybara"
require "sidekiq/testing"
Sidekiq::Testing.inline!
-# Add additional requires below this line. Rails is not loaded until this point!
# Requires supporting ruby files with custom matchers and macros, etc, in
# spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are