Commit 25e3e70
Changed files (58)
app
assets
models
views
training_sessions
db
migrate
spec
javascripts
app/assets/javascripts/models/google_drive.js.coffee
@@ -1,40 +0,0 @@
-class Stronglifters.GoogleDrive
- constructor: (options) ->
- @google = gapi
- @client_id = options.client_id
- @drive_upload_path = options.drive_upload_path
- @scopes = [
- 'https://www.googleapis.com/auth/drive',
- 'https://www.googleapis.com/auth/drive.install',
- 'https://www.googleapis.com/auth/drive.file',
- 'https://www.googleapis.com/auth/drive.readonly',
- 'https://www.googleapis.com/auth/drive.apps.readonly',
- ]
-
- syncFile: =>
- query = "title contains '.stronglifts' and title contains 'backup'"
- @searchFor query, @uploadFile
-
- searchFor: (query, callback) =>
- @loadDrive =>
- @google.client.drive.files.list({ 'q': query }).execute(callback)
-
- uploadFile: (response) =>
- item = response.items[0]
- $.post(@drive_upload_path, {
- accessToken: @google.auth.getToken().access_token,
- data: item
- }).done (data) ->
- window.location.reload()
-
- authorize: (callback) ->
- @google.auth.authorize({
- 'client_id': @client_id,
- 'scope': @scopes,
- 'immediate': false
- }, callback)
-
- loadDrive: (callback) =>
- @authorize (response) =>
- @google.load 'drive-share', =>
- @google.client.load 'drive', 'v2', callback
app/assets/javascripts/templates/exercise_view.ractive
@@ -1,22 +0,0 @@
-<!--
-<div class="panel small-12 columns">
- <div class="row">
- <div class="small-6 columns">
- {{name}}
- </div>
- <div class="small-6 columns">
- <p class="text-right">
- {{sets}}x{{repetitions}} {{target_weight}}lb
- </p>
- </div>
- </div>
-
- <div class="row">
- <div class="small-12 columns">
- {{#each reps}}
- <button on-click="updateProgress" class="button small round {{status}}">{{completed}}</button>
- {{/each}}
- </div>
- </div>
-</div>
--->
app/assets/javascripts/templates/training_session_view.ractive
@@ -1,33 +1,12 @@
<div class="row">
{{#each training_session.exercises}}
<div class="panel small-12 columns">
- {{name}}
- {{#if completed}}
- <div class="row">
- <div class="small-12 columns">
- Good Work!
- </div>
- </div>
- {{else}}
- <div class="row">
- <div class="small-12 columns">
- <p class="text-center">
- {{#each sets}}
- <button on-click="updateProgress" class="button small round {{status}}">
- {{completed}}
- </button>
- @ {{weight}} lb
- {{/each}}
- </p>
- </div>
- </div>
- <div class="row">
- <div class="small-12 columns">
- <button on-click="completeExercise" class="button expand">Done</button>
- </div>
- </div>
- {{/if}}
-
+ <h3>{{name}}</h3>
+ {{#each sets}}
+ <button on-click="updateProgress" class="button small round {{status}}">
+ {{actual_repetitions}}/{{target_repetitions}} @ {{target_weight}} lb
+ </button>
+ {{/each}}
</div>
{{/each}}
</div>
app/assets/javascripts/views/exercise_view.js.coffee
@@ -1,6 +0,0 @@
-#= require templates/exercise_view
-class Stronglifters.ExerciseView extends Ractive
- template: RactiveTemplates["templates/exercise_view"]
- data:
- workout_name: ''
-
app/assets/javascripts/views/training_session_view.js.coffee
@@ -3,44 +3,40 @@ class Stronglifters.TrainingSessionView extends Ractive
oninit: ->
@on 'updateProgress', (event) -> @updateProgress(event)
- @on 'completeExercise', (event) -> @completeExercise(event.context)
@observe 'training_session.exercises.*.sets.*', (newValue, oldValue, keypath) ->
@refreshStatus(newValue, oldValue, keypath)
updateProgress: (event) ->
- completed = @get("#{event.keypath}.completed")
+ completed = @get("#{event.keypath}.actual_repetitions")
if completed == null || completed == 0
- @set("#{event.keypath}.completed", @get("#{event.keypath}.target"))
+ @set("#{event.keypath}.actual_repetitions", @get("#{event.keypath}.target_repetitions"))
else
- @subtract("#{event.keypath}.completed")
+ @subtract("#{event.keypath}.actual_repetitions")
+ @saveSet(@get(event.keypath))
- refreshStatus: (newValue, oldValue, keyPath) ->
- if @get("#{keyPath}.completed") == 0
- @set("#{keyPath}.status", "secondary")
- return
-
- if @get("#{keyPath}.target") == @get("#{keyPath}.completed")
- @set("#{keyPath}.status", "success")
- else
- @set("#{keyPath}.status", "alert")
-
- completeExercise: (exercise) ->
- payload =
- training_session:
- exercise_id: exercise.id
- sets: _.map exercise.sets, (set) ->
- completed: set.completed
- weight: exercise.target_weight
- console.log(payload)
+ saveSet: (set) ->
+ @patch "/exercise_sets/#{set.id}",
+ exercise_set:
+ actual_repetitions: set.actual_repetitions
+ patch: (url, payload) ->
$.ajax
- url: "/training_sessions/#{@get('training_session.id')}",
+ url: url,
dataType: 'json',
type: 'patch',
contentType: 'application/json',
data: JSON.stringify(payload),
- success: (gym, statux, xhr) =>
- exercise.completed = true
- @updateModel()
+ success: (data, statux, xhr) =>
+ console.log(data)
error: (xhr, status, error) ->
console.log(error)
+
+ refreshStatus: (newValue, oldValue, keypath) ->
+ if @get("#{keypath}.actual_repetitions") == null
+ @set("#{keypath}.status", "secondary")
+ return
+
+ if @get("#{keypath}.target_repetitions") == @get("#{keypath}.actual_repetitions")
+ @set("#{keypath}.status", "success")
+ else
+ @set("#{keypath}.status", "alert")
app/controllers/exercise_sets_controller.rb
@@ -0,0 +1,13 @@
+class ExerciseSetsController < ApplicationController
+ def update
+ exercise_session = current_user.exercise_sets.find(params[:id])
+ exercise_session.update!(secure_params)
+ render json: {}
+ end
+
+ private
+
+ def secure_params
+ params.require(:exercise_set).permit(:actual_repetitions)
+ end
+end
app/controllers/training_sessions_controller.rb
@@ -1,36 +1,23 @@
class TrainingSessionsController < ApplicationController
- after_action :allow_google_iframe, only: [:index]
-
def index
@training_sessions = paginate(
current_user.
training_sessions.
- includes(:workout, :program, exercise_sessions: [:exercise]).
+ includes(:workout, :program, exercise_sets: [:exercise]).
order(occurred_at: :desc)
)
end
def new
@workout = current_user.next_workout
- @training_session = current_user.training_sessions.build(workout: @workout)
- @workout.exercise_workouts.each do |exercise|
- exercise_session = @training_session.exercise_sessions.build(exercise_workout: exercise)
- exercise.sets.times do
- exercise_session.exercise_sets.build(
- target_repetitions: exercise.repetitions,
- target_weight: current_user.next_weight_for(exercise.exercise)
- )
- end
- end
+ @training_session = current_user.next_training_session_for(@workout)
end
def create
- secure_params = params.require(:training_session).permit(:workout_id, :body_weight, exercise_sessions_attributes: [
- :exercise_workout_id,
- exercise_sets_attributes: [
- :target_repetitions,
- :target_weight,
- ]
+ 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(
@@ -45,43 +32,4 @@ class TrainingSessionsController < ApplicationController
def edit
@training_session = current_user.training_sessions.find(params[:id])
end
-
- def update
- #render json: params and return
- secure_params = params.require(:training_session).permit(:exercise_id, :weight, sets: [
- :weight,
- :completed
- ])
- @training_session = current_user.training_sessions.find(params[:id])
- secure_params[:sets].each_with_index do |set, index|
- @training_session.train(
- Exercise.find(secure_params[:exercise_id]),
- set[:weight],
- repetitions: set[:completed],
- set: index
- )
- end
- end
-
- def upload
- backup_file = BackupFile.new(current_user, params[:backup])
-
- if backup_file.valid?
- backup_file.process_later(Program.stronglifts)
- redirect_to dashboard_path, notice: t(".success")
- else
- redirect_to dashboard_path, alert: t(".failure")
- end
- end
-
- def drive_upload
- DownloadFromDriveJob.perform_later(current_user, params)
- redirect_to dashboard_path, notice: t(".success")
- end
-
- private
-
- def allow_google_iframe
- response.headers["X-Frame-Options"] = "ALLOW-FROM https://drive.google.com"
- end
end
app/jobs/download_from_drive_job.rb
@@ -1,9 +0,0 @@
-class DownloadFromDriveJob < ActiveJob::Base
- queue_as :default
-
- def perform(user, params)
- user.google_drive.download(params) do |backup_file|
- backup_file.process_later(Program.stronglifts)
- end
- end
-end
app/jobs/upload_stronglifts_backup_job.rb
@@ -19,8 +19,6 @@ class UploadStrongliftsBackupJob < ActiveJob::Base
def importer_for(directory, user, program)
[
- Android::Import.new(user, program),
- Ios::Import.new(user, program),
Csv::Import.new(user, program),
UnknownFile.new
].detect { |x| x.can_parse?(directory) }
app/models/android/import.rb
@@ -1,92 +0,0 @@
-class Android::Import
- attr_reader :user, :program
-
- def initialize(user, program)
- @user = user
- @program = program
- end
-
- def can_parse?(directory)
- File.exist?(database_file(directory))
- end
-
- def import_from(directory)
- database(directory) do |db|
- ActiveRecord::Base.transaction do
- db[:workouts].each do |row|
- import(row)
- end
- end
- end
- end
-
- private
-
- def import(row)
- create_workout_from(map_from(row))
- end
-
- def database_file(dir)
- "#{dir}/stronglifts.db"
- end
-
- def database(directory)
- yield Sequel.sqlite(database_file(directory))
- end
-
- def create_workout_from(workout_row)
- training_session_for(workout_row) do |training_session, workout|
- workout.exercise_workouts.each_with_index do |exercise_workout, index|
- exercise_row = workout_row.exercises[index]
- next if exercise_row.nil?
- sets_from(exercise_workout, exercise_row).each_with_index do |reps, set|
- training_session.train(
- exercise_workout.exercise,
- exercise_row["warmup"]["targetWeight"],
- repetitions: reps,
- set: set,
- )
- end
- end
- end
- end
-
- def training_session_for(workout_row)
- workout = program.workouts.find_by(name: workout_row.workout)
- user.begin_workout(
- workout,
- workout_row.date,
- workout_row.body_weight.to_f
- ).tap do |training_session|
- yield training_session, workout
- training_session
- end
- end
-
- def sets_from(exercise_workout, exercise_row)
- sets = []
- 1.upto(exercise_workout.sets).each do |n|
- if exercise_row["set#{n}"].to_i > 0
- sets << exercise_row["set#{n}"]
- else
- sets << 0
- end
- end
- sets
- end
-
- def map_from(row)
- Android::Workout.new(
- id: row[:id],
- date: user.time_zone.local_to_utc(row[:date]),
- workout: row[:workout],
- exercise_1: JSON.parse(row[:e1]),
- exercise_2: JSON.parse(row[:e2]),
- exercise_3: JSON.parse(row[:e3]),
- note: row[:note],
- body_weight: row[:bodyWeight],
- arm_work: row[:armWork].present? ? JSON.parse(row[:armWork]) : nil,
- temp: row[:temp]
- )
- end
-end
app/models/android/workout.rb
@@ -1,19 +0,0 @@
-class Android::Workout
- attr_accessor :id, :date, :workout
- attr_accessor :exercise_1, :exercise_2, :exercise_3
- attr_accessor :note, :body_weight, :arm_work, :temp
-
- def initialize(attributes = {})
- attributes.each do |attribute|
- send("#{attribute.first}=", attribute.last)
- end
- end
-
- def exercises
- @exercises ||= [
- exercise_1,
- exercise_2,
- exercise_3,
- ]
- end
-end
app/models/csv/import.rb
@@ -33,6 +33,7 @@ class Csv::Import
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(
exercise,
exercise_row.weight_lb,
app/models/ios/import.rb
@@ -1,72 +0,0 @@
-class Ios::Import
- attr_reader :user, :program
-
- def initialize(user, program)
- @user = user
- @program = program
- end
-
- def can_parse?(directory)
- File.exist?(database_file(directory))
- end
-
- def import_from(directory)
- database(directory) do |db|
- db[:ZBASEWORKOUT].each do |row|
- workout_name = row[:ZTYPE] == 1 ? "A" : "B"
- workout = program.workouts.find_by(name: workout_name)
- time = row[:ZDATE].to_s.split(' ')
- date_string = "#{row[:ZLOGDATE]} #{time[1]} #{time[2]}"
- occurred_at = DateTime.parse(date_string)
- body_weight = row[:ZBODYWEIGHT].to_f
- training_session = user.begin_workout(workout, occurred_at, body_weight)
-
- db[:ZEXERCISESETS].where(ZWORKOUT: row[:Z_PK]).
- each do |exercise_set_row|
- db[:ZEXERCISE].where(ZTYPE: exercise_set_row[:ZEXERCISETYPE]).
- each do |exercise_row|
- exercise = exercise_from(exercise_row)
- if exercise
- db[:ZWEIGHT].
- where(Z_PK: exercise_set_row[:ZWEIGHT]).each do |weight_row|
- target_weight = weight_row[:ZVAL]
- sets_from(exercise_set_row).each_with_index do |reps, set|
- training_session.train(exercise, target_weight, repetitions: reps, set: set)
- end
- end
- end
- end
- end
- end
- end
- end
-
- private
-
- def sets_from(row)
- (1..5).inject([]) do |memo, n|
- column = "ZSET#{n}".to_sym
- memo << row[column] if row[column] && row[column] != -3
- end || []
- end
-
- def database_file(directory)
- File.join(directory, "SLDB.sqlite")
- end
-
- def database(directory)
- yield Sequel.sqlite(database_file(directory))
- end
-
- def exercise_from(exercise_row)
- mapping = {
- 1 => "Squat",
- 2 => "Bench Press",
- 3 => "Barbell Row",
- 4 => "Overhead Press",
- 5 => "Deadlift",
- }
-
- program.exercises.find_by(name: mapping[exercise_row[:ZTYPE]])
- end
-end
app/models/exercise.rb
@@ -1,7 +1,4 @@
class Exercise < ActiveRecord::Base
- has_many :exercise_workouts
- has_many :workouts, through: :exercise_workouts
-
def short_name
name.gsub(/[^A-Z]/, "")
end
app/models/exercise_session.rb
@@ -1,21 +1,16 @@
-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
+#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
+ #def sets
+ #exercise_sets
+ #end
- #def target_weight
- ## shim for migrations
- #read_attribute(:target_weight) || sets.first.target_weight
+ #def to_sets
+ #sets.map(&:actual_repetitions)
#end
-end
+#end
app/models/exercise_set.rb
@@ -1,4 +1,4 @@
class ExerciseSet < ActiveRecord::Base
belongs_to :exercise_session
- has_one :exercise, through: :exercise_session
+ belongs_to :exercise
end
app/models/google_drive.rb
@@ -1,31 +0,0 @@
-class GoogleDrive
- attr_reader :user
-
- def initialize(user, referrer_domain: ENV["GOOGLE_REFERRER_DOMAIN"])
- @user = user
- @referrer_domain = referrer_domain
- end
-
- def download(params)
- Dir.mktmpdir do |dir|
- download_path = File.join(dir, params[:data][:title])
- url = params[:data][:downloadUrl].strip
- access_token = params[:accessToken]
- yield BackupFile.new(user, curl(url, download_path, access_token))
- end
- end
-
- private
-
- def curl(download_url, download_path, access_token)
- curl = Shell.new("curl")
- curl << "'#{download_url}'"
- curl << "-o '#{download_path}'"
- curl << "-H 'Authorization: Bearer #{access_token}'"
- curl << "-H 'Referer: #{@referrer_domain}/dashboard'"
- curl << "-H 'Origin: #{@referrer_domain}'"
- curl << "--compressed"
- curl.run
- File.new(download_path)
- end
-end
app/models/program.rb
@@ -2,6 +2,8 @@ class Program < ActiveRecord::Base
STRONG_LIFTS = "StrongLifts 5ร5"
has_many :exercises, through: :workouts
has_many :workouts
+ has_many :exercise_workouts, through: :workouts
+
before_save do
self.slug = name.parameterize
end
@@ -20,6 +22,29 @@ class Program < ActiveRecord::Base
workouts.where.not(name: workout.name).first
end
+ def prepare_sets_for(user, exercise)
+ recommended_sets_for(user, exercise).times.map do
+ ExerciseSet.new(
+ exercise: exercise,
+ target_repetitions: recommended_reps_for(user, exercise),
+ target_weight: user.next_weight_for(exercise)
+ )
+ end
+ 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
+ end
+
+ def recommended_reps_for(user, exercise)
+ recommendation_for(user, exercise).repetitions
+ end
+
+ def recommendation_for(user, exercise)
+ exercise_workouts.find_by(exercise: exercise)
+ end
+
class << self
def stronglifts
Program.find_by(name: STRONG_LIFTS)
app/models/progress.rb
@@ -0,0 +1,20 @@
+class Progress
+ attr_reader :exercise, :training_session
+
+ def initialize(training_session, exercise)
+ @exercise = exercise
+ @training_session = training_session
+ end
+
+ def to_sets
+ sets.pluck(:actual_repetitions)
+ end
+
+ def max_weight
+ sets.maximum(:target_weight)
+ end
+
+ def sets
+ training_session.exercise_sets.where(exercise: exercise).order(:created_at)
+ end
+end
app/models/shell.rb
@@ -1,20 +0,0 @@
-class Shell
- def initialize(program)
- @program = program
- @options = []
- end
-
- def <<(option)
- @options.push(option)
- end
-
- def run
- `#{build_command}`
- end
-
- private
-
- def build_command
- "#{@program} #{@options.join(' ')}"
- end
-end
app/models/training_history.rb
@@ -16,18 +16,21 @@ class TrainingHistory
end
def completed_any?
- user.
- exercise_sessions.
- joins(:exercise).
- any?
+ user.exercise_sets.where(exercise: exercise).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
end
def last_weight
user.
- exercise_sessions.
+ exercise_sets.
joins(:exercise).
- joins(:training_session).
where(exercises: { id: exercise.id }).
+ where('actual_repetitions = target_repetitions').
order('training_sessions.occurred_at').
last.try(:target_weight).to_i
end
@@ -37,14 +40,10 @@ class TrainingHistory
end
def to_line_chart
- user.
- exercise_sessions.
- includes(:training_session).
- joins(:exercise).
- where(exercises: { name: exercise.name }).
- inject({}) do |memo, session|
- memo[session.training_session.occurred_at] = session.sets.first.target_weight
- memo
- end
+ user.training_sessions.inject({}) do |memo, training_session|
+ memo[training_session.occurred_at] =
+ training_session.exercise_sets.where(exercise: exercise).maximum(:target_weight)
+ memo
+ end
end
end
app/models/training_session.rb
@@ -2,26 +2,29 @@ class TrainingSession < ActiveRecord::Base
belongs_to :user
belongs_to :workout
has_one :program, through: :workout
- has_many :exercise_sessions, dependent: :destroy
- has_many :exercises, through: :exercise_sessions
- accepts_nested_attributes_for :exercise_sessions
+ 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)
- recommendation = workout.exercise_workouts.find_by(exercise: exercise)
-
- session = exercise_sessions.find_or_create_by(exercise_workout: recommendation)
- exercise_set = set.present? && session.sets.at(set).present? ? session.sets.at(set) : session.sets.build
- exercise_set.update!(
- actual_repetitions: repetitions,
- target_repetitions: recommendation.repetitions,
- target_weight: target_weight,
- )
- session
+ 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)
- exercise_sessions.
- joins(exercise_workout: :exercise).
- find_by(exercise_workouts: { exercise_id: exercise.id })
+ Progress.new(self, exercise)
+ end
+
+ def sets
+ exercise_sets
end
end
app/models/user.rb
@@ -2,8 +2,7 @@ class User < ActiveRecord::Base
include Flippable
has_secure_password
has_many :training_sessions
- has_many :exercise_sessions, through: :training_sessions
- has_many :exercise_sets, through: :exercise_sessions
+ has_many :exercise_sets, through: :training_sessions
has_many :user_sessions, dependent: :destroy
has_one :profile
has_many :received_emails
@@ -89,12 +88,27 @@ class User < ActiveRecord::Base
last_workout.next_workout
end
- def current_program
- Program.stronglifts
+ 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)
+ end
end
- def google_drive
- GoogleDrive.new(self)
+ def last_training_session(exercise = nil)
+ if exercise.present?
+ training_sessions.
+ joins(:exercises).
+ where(exercises: { id: exercise.id }).
+ order(:created_at).
+ last
+ else
+ training_sessions.order(:created_at).last
+ end
+ end
+
+ def current_program
+ Program.stronglifts
end
class << self
app/models/workout.rb
@@ -26,4 +26,10 @@ class Workout < ActiveRecord::Base
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
+ end
end
app/views/training_sessions/_training_session.html.erb
@@ -5,8 +5,8 @@
<td><%= I18n.l training_session.occurred_at, format: :short %></td>
<td><%= training_session.body_weight %> lbs</td>
<td>
- <% training_session.exercise_sessions.each do |exercise_session| %>
- <strong><%= exercise_session.exercise.name %></strong> @ <%= exercise_session.sets.maximum(:target_weight) %> lbs,
+ <% 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>
app/views/training_sessions/_training_session.jbuilder
@@ -1,13 +1,13 @@
json.id training_session.id
json.body_weight training_session.body_weight
json.workout_name training_session.workout.name
-json.exercises training_session.exercise_sessions.order(:created_at) do |exercise|
- json.id exercise.exercise.id
+json.exercises training_session.exercise_sets.order(:created_at).group_by(&:exercise) do |exercise, exercise_sets|
+ json.id exercise.id
json.name exercise.name
- json.sets exercise.sets.order(:created_at) do |set|
- json.weight set.target_weight
- json.target set.target_repetitions
- json.completed set.actual_repetitions
+ json.sets exercise_sets.sort_by(&:created_at) do |set|
+ json.id set.id
+ json.target_weight set.target_weight
+ json.target_repetitions set.target_repetitions
+ json.actual_repetitions set.actual_repetitions
end
- json.target_weight current_user.next_weight_for(exercise.exercise)
end
app/views/training_sessions/edit.html.erb
@@ -1,6 +1,5 @@
<div class="row">
<div class="large-12 columns">
-<% render partial: 'edit.json.jbuilder', locals: { training_session: @training_session } %>;
<div id="training-session-view"></div>
<%= link_to t(:back_html), training_sessions_path %>
</div>
app/views/training_sessions/new.html.erb
@@ -5,12 +5,11 @@
<legend><%= TrainingSession.human_attribute_name(:body_weight) %></legend>
<%= f.number_field :body_weight %>
</fieldset>
- <% @training_session.exercise_sessions.each do |exercise_session| %>
- <%= f.fields_for :exercise_sessions, exercise_session do |e| %>
+ <% @training_session.exercise_sets.group_by(&:exercise).each do |exercise, exercise_sets| %>
<fieldset>
- <legend><%= e.object.exercise.name %></legend>
- <% exercise_session.exercise_sets.each.with_index(1) do |set, index| %>
- <%= e.fields_for :exercise_sets, set do |s| %>
+ <legend><%= exercise.name %></legend>
+ <% exercise_sets.each.with_index(1) do |set, index| %>
+ <%= f.fields_for :exercise_sets, set do |s| %>
<fieldset>
<legend>Set <%= index %></legend>
<div class="row">
@@ -24,13 +23,13 @@
<%= s.number_field :target_weight %>
</div>
</div>
+ <%= s.hidden_field :exercise_id %>
</fieldset>
<% end %>
<% end %>
- <%= e.hidden_field :exercise_workout_id %>
+ <%= f.hidden_field :workout_id %>
</fieldset>
- <% end %>
<% end %>
<%= f.hidden_field :workout_id %>
<%= f.submit "Start", class: "button round right" %>
config/locales/en.yml
@@ -93,8 +93,6 @@ en:
login_button: "Login"
register_link: "Create an account"
training_sessions:
- drive_upload:
- success: 'Our minions have been summoned to fetch your backup.'
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
@@ -102,8 +100,5 @@ en:
lead: Your custom email address.
title: Send-to-Stronglifters.
warning: To ensure your workouts are imported correctly we suggest that you update your timezone.
- upload:
- success: "Our minions have been summoned to unpack your backup."
- failure: "We don't know how to unpack this type of file."
footer:
copyright: "ยฉ Copyright www.stronglifters.com. All rights reserved."
config/routes.rb
@@ -2,12 +2,8 @@ Rails.application.routes.draw do
root "sessions#new"
resources :sessions, only: [:new, :create, :destroy]
resources :registrations, only: [:new, :create]
- resources :training_sessions, only: [:index, :new, :create, :edit, :update] do
- collection do
- post :upload
- post :drive_upload
- end
- end
+ resources :exercise_sets, only: [:update]
+ resources :training_sessions, 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]
db/migrate/20160623202628_add_exercise_id_to_exercise_sets.rb
@@ -0,0 +1,5 @@
+class AddExerciseIdToExerciseSets < ActiveRecord::Migration
+ def change
+ add_column :exercise_sets, :exercise_id, :uuid
+ end
+end
db/migrate/20160623202817_migrate_exercise_id_to_exercise_sets.rb
@@ -0,0 +1,8 @@
+class MigrateExerciseIdToExerciseSets < ActiveRecord::Migration
+ def change
+ ExerciseSet.where(exercise_id: nil).find_each do |set|
+ set.exercise = set.exercise_session.exercise
+ set.save!
+ end
+ end
+end
db/migrate/20160623203043_make_exercise_id_not_null.rb
@@ -0,0 +1,5 @@
+class MakeExerciseIdNotNull < ActiveRecord::Migration
+ def change
+ change_column :exercise_sets, :exercise_id, :uuid, null: false
+ end
+end
db/migrate/20160623205223_add_training_session_id_to_exercise_sets.rb
@@ -0,0 +1,5 @@
+class AddTrainingSessionIdToExerciseSets < ActiveRecord::Migration
+ def change
+ add_column :exercise_sets, :training_session_id, :uuid
+ end
+end
db/migrate/20160623205309_migrate_training_session_id_to_exercise_sets.rb
@@ -0,0 +1,8 @@
+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!
+ end
+ end
+end
db/migrate/20160624002057_drop_exercise_session_id_from_exercise_sets.rb
@@ -0,0 +1,5 @@
+class DropExerciseSessionIdFromExerciseSets < ActiveRecord::Migration
+ def change
+ remove_column :exercise_sets, :exercise_session_id
+ end
+end
db/migrate/20160624034644_remove_exercise_sessions.rb
@@ -0,0 +1,5 @@
+class RemoveExerciseSessions < ActiveRecord::Migration
+ def change
+ drop_table :exercise_sessions
+ end
+end
db/schema.rb
@@ -11,26 +11,20 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20160611171913) do
+ActiveRecord::Schema.define(version: 20160624034644) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
enable_extension "uuid-ossp"
- create_table "exercise_sessions", id: :uuid, default: "uuid_generate_v4()", force: :cascade do |t|
- t.uuid "training_session_id", null: false
- t.uuid "exercise_workout_id", null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- end
-
create_table "exercise_sets", id: :uuid, default: "uuid_generate_v4()", force: :cascade do |t|
- t.uuid "exercise_session_id", null: false
- t.integer "target_repetitions"
+ t.integer "target_repetitions", null: false
t.integer "actual_repetitions"
- t.float "target_weight"
+ 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"
end
create_table "exercise_workouts", id: :uuid, default: "uuid_generate_v4()", force: :cascade do |t|
spec/controllers/exercise_sets_controller_spec.rb
@@ -0,0 +1,26 @@
+require "rails_helper"
+
+describe ExerciseSetsController do
+ let(:user) { create(:user) }
+
+ before :each do
+ http_login(user)
+ end
+
+ describe "#update" do
+ include_context "stronglifts_program"
+ let(:training_session) { user.next_training_session_for(workout_a) }
+
+ it "records the exercise" do
+ training_session.update!(occurred_at: DateTime.now, body_weight: 225)
+ exercise_set = training_session.exercise_sets.first
+
+ xhr :patch, :update, id: exercise_set.id, exercise_set: {
+ actual_weight: 315,
+ actual_repetitions: 5,
+ }
+ expect(response).to have_http_status(:ok)
+ expect(exercise_set.reload.actual_repetitions).to eql(5)
+ end
+ end
+end
spec/controllers/training_sessions_controller_spec.rb
@@ -16,74 +16,6 @@ describe TrainingSessionsController do
get :index
expect(assigns(:training_sessions)).to match_array([training_session_a, training_session_b])
end
-
- it "allows iframes from google for the google drive popup" do
- get :index
- allowed_url = "ALLOW-FROM https://drive.google.com"
- expect(response.headers["X-Frame-Options"]).to eql(allowed_url)
- end
- end
-
- describe "#upload" do
- include_context "stronglifts_program"
- let(:backup_file) { fixture_file_upload("backup.android.stronglifts") }
- let(:translation) { I18n.translate("training_sessions.upload.success") }
-
- before :each do
- allow(UploadStrongliftsBackupJob).to receive(:perform_later)
- end
-
- it "uploads a new backup" do
- post :upload, backup: backup_file
- expect(UploadStrongliftsBackupJob).to have_received(:perform_later)
- end
-
- it "redirects to the dashboard" do
- post :upload, backup: backup_file
- expect(response).to redirect_to(dashboard_path)
- end
-
- it "displays a friendly message" do
- post :upload, backup: backup_file
- expect(flash[:notice]).to eql(translation)
- end
-
- context "when the file is not a backup file" do
- let(:unknown_file) { fixture_file_upload("unknown.file") }
-
- it "displays an error" do
- post :upload, backup: unknown_file
- translation = I18n.translate("training_sessions.upload.failure")
- expect(flash[:alert]).to eql(translation)
- expect(response).to redirect_to(dashboard_path)
- end
- end
- end
-
- describe "#drive_upload" do
- let(:params) { {} }
- let(:success_message) do
- I18n.translate("training_sessions.drive_upload.success")
- end
-
- before :each do
- allow(DownloadFromDriveJob).to receive(:perform_later)
- end
-
- it "schedules a job to suck down the latest backup from google drive" do
- post :drive_upload, params
- expect(DownloadFromDriveJob).to have_received(:perform_later)
- end
-
- it "redirects to the dashboard" do
- post :drive_upload, params
- expect(response).to redirect_to(dashboard_path)
- end
-
- it "displays a success message" do
- post :drive_upload, params
- expect(flash[:notice]).to eql(success_message)
- end
end
describe "#new" do
@@ -123,25 +55,19 @@ describe TrainingSessionsController do
post :create, training_session: {
workout_id: workout_b.id,
body_weight: body_weight,
- exercise_sessions_attributes: [
- {
- exercise_workout_id: workout_b.exercise_workouts.first.id,
- #target_repetitions: 4,
- #target_sets: 3,
- #target_weight: 275.0,
- }
- ]
+ 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.exercise_sessions.count).to eql(1)
- exercise_session = training_session.exercise_sessions.first
- #expect(exercise_session.target_sets).to eql(3)
- #expect(exercise_session.target_repetitions).to eql(4)
- #expect(exercise_session.target_weight).to eql(275.0)
+ 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
@@ -154,20 +80,4 @@ describe TrainingSessionsController do
expect(assigns(:training_session)).to eql(training_session)
end
end
-
- describe "#update" do
- include_context "stronglifts_program"
- let(:training_session) { create(:training_session, user: user, workout: workout_a) }
-
- it "records the exercise" do
- xhr :patch, :update, id: training_session.id, training_session: {
- exercise_id: squat.id,
- weight: 315,
- sets: [5, 5, 5],
- }
- expect(training_session.exercises).to include(squat)
- expect(training_session.progress_for(squat).sets.first.target_weight).to eql(315.to_f)
- expect(training_session.progress_for(squat).to_sets).to eql([5, 5, 5])
- end
- end
end
spec/fixtures/backup.android.stronglifts
Binary file
spec/fixtures/backup.ios.stronglifts
Binary file
spec/jobs/download_from_drive_job_spec.rb
@@ -1,17 +0,0 @@
-require "rails_helper"
-
-RSpec.describe DownloadFromDriveJob, type: :job do
- describe "#perform" do
- let(:user) { build(:user) }
- let(:params) { {} }
- let(:backup_file) { double(process_later: true) }
- let(:drive) { instance_double(GoogleDrive) }
-
- it "downloads the file for further processing" do
- allow(user).to receive(:google_drive).and_return(drive)
- allow(drive).to receive(:download).with(params).and_yield(backup_file)
- subject.perform(user, params)
- expect(backup_file).to have_received(:process_later).with(Program.stronglifts)
- end
- end
-end
spec/jobs/upload_stronglifts_backup_job_spec.rb
@@ -5,30 +5,6 @@ describe UploadStrongliftsBackupJob, type: :job do
let(:user) { create(:user) }
describe "#perform" do
- context "android backup" do
- let(:backup_file) do
- Rails.root.join("spec", "fixtures", "backup.android.stronglifts").to_s
- end
-
- 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(31)
- end
- end
-
- context "ios backup" do
- let(:backup_file) do
- Rails.root.join("spec", "fixtures", "backup.ios.stronglifts").to_s
- end
-
- 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(9)
- end
- end
-
context "csv export" do
let(:backup_file) do
Rails.root.join("spec", "fixtures", "spreadsheet-stronglifts.csv").to_s
spec/models/android/import_spec.rb
@@ -1,69 +0,0 @@
-require "rails_helper"
-
-describe Android::Import do
- include_context "stronglifts_program"
- subject { Android::Import.new(user, program) }
- let(:user) { create(:user) }
-
- describe "#import_from" do
- let(:directory) { Dir.mktmpdir }
- let(:backup_file) do
- Rails.root.join("spec", "fixtures", "backup.android.stronglifts")
- end
-
- before :each do
- `unzip #{backup_file} -d #{directory}`
- end
-
- after :each do
- FileUtils.remove_entry(directory)
- end
-
- it "imports each training session" do
- mountain_time = ActiveSupport::TimeZone["America/Denver"]
- allow(user).to receive(:time_zone).and_return(mountain_time)
- subject.import_from(directory)
- training_session = user.training_sessions.order(:occurred_at).first
-
- expected_date = DateTime.new(2015, 03, 02, 16, 28, 26)
- expect(training_session.occurred_at.to_i).to eql(expected_date.to_i)
- expect(training_session.workout).to eql(workout_a)
- expect(training_session.body_weight).to eql(205.0)
- expect(training_session.exercise_sessions.count).to eql(3)
- expect(
- training_session.exercise_sessions.map { |x| x.exercise.name }
- ).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)
-
- expect(squat_session.to_sets).to eql([5, 5, 5, 5, 5])
- end
-
- 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)
- expect(bench_session.to_sets).to eql([5, 5, 5, 5, 5])
- end
-
- 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)
- expect(row_session.to_sets).to eql([5, 5, 5, 5, 5])
- end
-
- it "excludes items that have already been imported" do
- subject.import_from(directory)
- subject.import_from(directory)
- expect(user.training_sessions.count).to eql(31)
- end
- end
-end
spec/models/csv/import_spec.rb
@@ -48,9 +48,9 @@ describe Csv::Import do
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_sessions.count).to eql(3)
+ expect(training_session.exercise_sets.count).to eql(15)
expect(
- training_session.exercise_sessions.map { |x| x.exercise.name }
+ training_session.exercise_sets.map { |x| x.exercise.name }.uniq
).to match_array(["Squat", "Bench Press", "Barbell Row"])
end
@@ -103,9 +103,9 @@ describe Csv::Import do
subject.import(row)
training_session = user.training_sessions.first
- session = training_session.progress_for(dips)
- expect(session).to_not be_nil
- expect(session.to_sets).to eql([5, 5, 5])
+ progress = training_session.progress_for(dips)
+ expect(progress).to_not be_nil
+ expect(progress.to_sets).to eql([5, 5, 5])
end
it "imports chinups" do
@@ -113,18 +113,30 @@ describe Csv::Import do
subject.import(row)
training_session = user.training_sessions.first
- session = training_session.progress_for(chinups)
- expect(session).to_not be_nil
- expect(session.to_sets).to eql([5, 3, 2])
- expect(session.sets.at(0).target_weight).to eql(0.0)
- expect(session.sets.at(0).target_repetitions).to eql(5)
- expect(session.sets.at(0).actual_repetitions).to eql(5)
- expect(session.sets.at(1).target_weight).to eql(0.0)
- expect(session.sets.at(1).target_repetitions).to eql(5)
- expect(session.sets.at(1).actual_repetitions).to eql(3)
- expect(session.sets.at(2).target_weight).to eql(0.0)
- expect(session.sets.at(2).target_repetitions).to eql(5)
- expect(session.sets.at(2).actual_repetitions).to eql(2)
+ progress = training_session.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)
+ 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).target_weight).to eql(0.0)
+ 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).target_weight).to eql(0.0)
+ expect(progress.sets.at(2).target_repetitions).to eql(5)
+ expect(progress.sets.at(2).actual_repetitions).to eql(2)
+ end
+
+ it 'imports the correct number of sets' 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])
+
+ expect(training_session.progress_for(deadlift).sets.count).to eql(1)
+ expect(training_session.progress_for(deadlift).to_sets).to eql([5])
end
end
end
spec/models/ios/import_spec.rb
@@ -1,95 +0,0 @@
-require "rails_helper"
-
-describe Ios::Import do
- include_context "stronglifts_program"
- subject { Ios::Import.new(user, program) }
- let(:user) { create(:user) }
-
- describe "#can_parse?" do
- let(:directory) { Dir.mktmpdir }
-
- context "when the directory contains the ios backup db" do
- before :each do
- FileUtils.touch("#{directory}/SLDB.sqlite")
- end
-
- it "returns true" do
- expect(subject.can_parse?(directory)).to be_truthy
- end
- end
-
- context "when the directory does not have the ios backup db" do
- it "returns false" do
- expect(subject.can_parse?(directory)).to be_falsey
- end
- end
- end
-
- describe "#import_from" do
- let(:directory) { Dir.mktmpdir }
- let(:backup_file) do
- Rails.root.join("spec", "fixtures", "backup.ios.stronglifts")
- end
-
- before :each do
- `unzip #{backup_file} -d #{directory}`
- end
-
- after :each do
- FileUtils.remove_entry(directory)
- end
-
- it "imports each workout" do
- subject.import_from(directory)
- expect(user.training_sessions.count).to eql(9)
- end
-
- it "imports each training session" do
- subject.import_from(directory)
- training_sessions = user.training_sessions.order(:occurred_at)
- training_session = training_sessions.first
- first_exercises = training_session.exercise_sessions
- expect(first_exercises.count).to eql(3)
- expect(first_exercises.first.to_sets).to eql([5, 5, 5, 5, 5])
-
- expected_date = DateTime.new(2015, 05, 02, 23, 27, 05)
- expect(training_session.occurred_at.to_i).to eql(expected_date.to_i)
- expect(training_session.workout).to eql(workout_a)
- expect(training_session.body_weight).to eql(160.0)
- expect(training_session.exercise_sessions.count).to eql(3)
- expect(
- training_session.exercise_sessions.map { |x| x.exercise.name }
- ).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)
- expect(squat_session.to_sets).to eql([5, 5, 5, 5, 5])
- end
-
- 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)
- expect(bench_session.to_sets).to eql([5, 5, 5, 5, 5])
- end
-
- 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)
- expect(row_session.to_sets).to eql([5, 5, 5, 5, 5])
- end
-
- it "excludes items that have already been imported" do
- subject.import_from(directory)
- subject.import_from(directory)
- expect(user.training_sessions.count).to eql(9)
- end
- end
-end
spec/models/backup_file_spec.rb
@@ -8,11 +8,6 @@ describe BackupFile do
end
describe "#valid?" do
- it "returns true" do
- subject = BackupFile.new(user, fixture_file("backup.android.stronglifts"))
- expect(subject).to be_valid
- end
-
it "returns true for csv exports" do
csv_export = fixture_file("spreadsheet-stronglifts.csv")
subject = BackupFile.new(user, csv_export)
@@ -30,7 +25,7 @@ describe BackupFile do
it "creates a job to process later" do
allow(UploadStrongliftsBackupJob).to receive(:perform_later)
- subject = BackupFile.new(user, fixture_file("backup.ios.stronglifts"))
+ subject = BackupFile.new(user, fixture_file("spreadsheet-stronglifts.csv"))
subject.process_later(program)
expect(UploadStrongliftsBackupJob).to have_received(:perform_later)
end
spec/models/google_drive_spec.rb
@@ -1,32 +0,0 @@
-require "rails_helper"
-
-describe GoogleDrive do
- subject { GoogleDrive.new(user) }
- let(:user) { build(:user) }
- let(:referrer_domain) { "https://www.stronglifters.com" }
-
- describe "#download" do
- let(:params) do
- {
- accessToken: access_token,
- data: {
- title: filename,
- downloadUrl: "https://www.google.com/"
- },
- }
- end
-
- let(:filename) { "#{FFaker::Internet.user_name}.html" }
- let(:access_token) { FFaker::Internet.user_name }
-
- it "downloads the specified google drive file", skip: true do
- result = nil
- subject.download(params) do |backup_file|
- result = backup_file
- end
- expect(result).to_not be_nil
- expect(result.user).to eql(user)
- expect(result.backup_file.path).to end_with(filename)
- end
- end
-end
spec/models/training_history_spec.rb
@@ -14,6 +14,7 @@ describe TrainingHistory do
session = user.begin_workout(workout_a, date, body_weight)
5.times do
session.train(squat, target_weight, repetitions: 5)
+ session.train(bench_press, target_weight + 10, repetitions: 5)
end
end
@@ -21,6 +22,7 @@ describe TrainingHistory do
result = subject.to_line_chart
expect(result).to_not be_nil
expect(result.keys.first.to_i).to eql(date.to_i)
+ expect(result.keys.count).to eql(1)
expect(result.values.first).to eql(target_weight.to_f)
end
end
spec/models/training_session_spec.rb
@@ -17,11 +17,11 @@ describe TrainingSession, type: :model do
expect(result).to be_persisted
expect(result.exercise).to eql(squat)
- expect(result.to_sets).to eql([5])
- expect(result.sets.at(0).exercise).to eql(squat)
- expect(result.sets.at(0).target_weight).to eql(target_weight.to_f)
- expect(result.sets.at(0).target_repetitions).to eql(5)
- expect(result.sets.at(0).actual_repetitions).to eql(5)
+ 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
@@ -30,15 +30,15 @@ describe TrainingSession, type: :model do
expect(result).to be_persisted
expect(result.exercise).to eql(squat)
- expect(result.to_sets).to eql([5, 3])
- expect(result.sets.at(0).exercise).to eql(squat)
- expect(result.sets.at(0).target_weight).to eql(target_weight.to_f)
- expect(result.sets.at(0).target_repetitions).to eql(5)
- expect(result.sets.at(0).actual_repetitions).to eql(5)
- expect(result.sets.at(1).exercise).to eql(squat)
- expect(result.sets.at(1).target_weight).to eql(target_weight.to_f)
- expect(result.sets.at(1).target_repetitions).to eql(5)
- expect(result.sets.at(1).actual_repetitions).to eql(3)
+ 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
@@ -51,37 +51,40 @@ describe TrainingSession, type: :model do
expect(result).to be_persisted
expect(result.exercise).to eql(squat)
- expect(result.to_sets).to eql([5, 3, 5])
- expect(result.sets.at(0).exercise).to eql(squat)
- expect(result.sets.at(0).target_weight).to eql(target_weight.to_f)
- expect(result.sets.at(0).target_repetitions).to eql(5)
- expect(result.sets.at(0).actual_repetitions).to eql(5)
- expect(result.sets.at(1).exercise).to eql(squat)
- expect(result.sets.at(1).target_weight).to eql(new_weight.to_f)
- expect(result.sets.at(1).target_repetitions).to eql(5)
- expect(result.sets.at(1).actual_repetitions).to eql(3)
- expect(result.sets.at(2).exercise).to eql(squat)
- expect(result.sets.at(2).target_weight).to eql(target_weight.to_f)
- expect(result.sets.at(2).target_repetitions).to eql(5)
- expect(result.sets.at(2).actual_repetitions).to eql(5)
+ 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
- result = subject.train(squat, target_weight, repetitions: 5)
- subject.train(squat, target_weight, repetitions: 5)
+ subject.train(squat, target_weight, repetitions: 5, set: 0)
+ subject.train(squat, target_weight, repetitions: 5, set: 0)
- expect(subject.exercise_sessions.count).to eql(1)
- expect(subject.exercise_sessions).to match_array([result])
+ 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
spec/models/user_spec.rb
@@ -157,14 +157,6 @@ describe User do
end
end
- describe "#google_drive" do
- it "returns the users google drive" do
- result = subject.google_drive
- expect(result).to be_instance_of(GoogleDrive)
- expect(result.user).to eql(subject)
- end
- end
-
describe "when destroying a training session" do
include_context "stronglifts_program"
subject { create(:user) }
@@ -180,7 +172,7 @@ describe User do
subject.training_sessions.destroy_all
expect(TrainingSession.all).to be_empty
- expect(ExerciseSession.all).to be_empty
+ expect(ExerciseSet.all).to be_empty
end
end
.env.example
@@ -1,6 +1,4 @@
DEFAULT_FROM_ADDRESS=''
-GOOGLE_CLIENT_ID=''
-GOOGLE_REFERRER_DOMAIN=http://stronglifters.dev
SMTP_DOMAIN='stronglifters.com'
SMTP_HOST=''
SMTP_PASSWORD=''
Gemfile
@@ -53,14 +53,12 @@ source "https://rubygems.org" do
gem "sass-rails", "~> 5.0"
gem "scale"
gem "sdoc", "~> 0.4", group: :doc
- gem "sequel"
gem "sidekiq"
gem "spring", group: [:development, :test]
gem "spring-commands-cucumber", group: :test
gem "spring-commands-rspec", group: :test
gem "spring-commands-teaspoon", group: :test
gem "sprockets-rails", "2.3.3"
- gem "sqlite3"
gem "stackprof", group: :development
gem "teaspoon-jasmine", group: :test
gem "therubyracer", platforms: :ruby
Gemfile.lock
@@ -352,7 +352,6 @@ GEM
sdoc (0.4.1)
json (~> 1.7, >= 1.7.7)
rdoc (~> 4.0)
- sequel (4.33.0)
sexp_processor (4.7.0)
sidekiq (4.1.1)
concurrent-ruby (~> 1.0)
@@ -381,7 +380,6 @@ GEM
actionpack (>= 3.0)
activesupport (>= 3.0)
sprockets (>= 2.8, < 4.0)
- sqlite3 (1.3.11)
sshkit (1.10.0)
net-scp (>= 1.1.2)
net-ssh (>= 2.8.0)
@@ -497,14 +495,12 @@ DEPENDENCIES
sass-rails (~> 5.0)!
scale!
sdoc (~> 0.4)!
- sequel!
sidekiq!
spring!
spring-commands-cucumber!
spring-commands-rspec!
spring-commands-teaspoon!
sprockets-rails (= 2.3.3)!
- sqlite3!
stackprof!
teaspoon-jasmine!
therubyracer!