Commit 6a1bc50

mo khan <mo@mokhan.ca>
2016-06-24 23:24:50
refactor model.
1 parent 5514ec6
Changed files (68)
app
config
db
spec
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