0

Just trying to create a simple workout log here I'm getting this error when I try and create weights

"Workout ID must exist"

Models

class Workout < ApplicationRecord
 belongs_to :user
 has_many :exercises
 has_many :weights, through: :exercises
 accepts_nested_attributes_for :exercises, :allow_destroy => true
 accepts_nested_attributes_for :weights, :allow_destroy => true
 validates :bodypart, presence: true, length: { maximum: 255 }
end

class Weight < ApplicationRecord
  belongs_to :exercise
  belongs_to :workout
  validates :amount, presence: true, length: { maximum: 255 }
  validates :reps, presence: true, length: { maximum: 255 }
end

class Exercise < ApplicationRecord
  belongs_to :workout
  has_many :weights
  accepts_nested_attributes_for :weights
  validates :name, presence: true
  validates_associated :weights
end

After reading a few things I thought that a has many through would be the option for these associations but now I'm not so sure. When I try and create a weight for exercise I get the exercise ID but can't seem to get the workout ID despite a number of attempts. I'm not sure if its simply a controller issue or if Im missing something bigger here.

My Current Weights Controller

class WeightsController < ApplicationController
 before_action :authenticate_user!

def new
 @weight = Weight.new
end

 def create
   @exercise = Exercise.find(params[:exercise_id])
   @weight = @exercise.weights.build(weight_params)
 if @weight.save
   flash[:notice] = "Set saved"
   redirect_to exercise_path(@exercise)
 else
   redirect_to exercise_path(@exercise)
   flash[:notice] = "#{@weight.errors.full_messages.to_sentence}"
 end
end

def edit
end

def update
end

def destroy
 weight = Weight.find(params[:id])
 @weight.destroy
 redirect_to root_path
end

private

def weight_params
 params.require(:weight).permit(:amount, :reps)
end

end

Routes.rb

Rails.application.routes.draw do

devise_for :users, controllers: { omniauth_callbacks: "callbacks" }
root 'articles#index'

get '/demo', to: 'static_pages#demo'
get '/about', to: 'static_pages#about'
get '/test', to: 'static_pages#index'

resources :articles

resources :workouts do
    resources :exercises
end

resources :exercises do
    resources :weights
end

resources :workouts do
    member do
        put :is_finished
        put :unfinish
    end
end

resources :exercises do
    member do
        put :is_finished
        put :unfinish
    end
end

resources :books, :only => :index
end

Exercises controller

class ExercisesController < ApplicationController
 before_action :authenticate_user!
 # before_action :set_exercise, except: [:index, :new, :create]

def new
 @exercise = Exercise.new
 @exercise.weights.new
end

def index
 @workout = Workout.find(params[:workout_id])
 @exercise = @workout.exercises
end

def create
 @workout = Workout.find(params[:workout_id])
 @exercise = @workout.exercises.build(exercise_params)
   if @exercise.save
     redirect_to workout_exercise_path(@workout, @exercise)
     flash[:notice] = "Exercise created, enter weight and reps for      your first set"
  else 
    redirect_to @workout
    flash[:notice] = "#{@exercise.errors.full_messages.to_sentence}"
  end
 end

def edit
end

def update
 @exercise = Exercise.find(params[:id])
 if @exercise.update_attributes(exercise_params)
   redirect_to exercise_path(@exercise)
 else
  flash[:notice] = "Something went wrong"
 end
end

def show
 @exercise = Exercise.find(params[:id])
 @weights = @exercise.weights.order('created_at DESC').paginate(page:     params[:page], per_page: 5)
end

I do have an ID column for workout_id set on my Weights model but it always populates NULL whenever I can manage to create an exercise. Also, in the rails console I can find a workout and call @workout.weights and it returns the weights associated with the workout just fine. I just can't get the workout ID to populate in Weight model. Wondering if has and belongs to many would be better OR if my has many through is just set up wrong. I did try "inverse_of" without any luck. Any help would be appreciated.

Mark Hustad
  • 169
  • 1
  • 14

1 Answers1

0

The answer is quite simple. To add reverse functionality, you have to explicitly state it, through the exercise.

in weight.rb remove belongs_to :workout and add the following

def workout
    self.exercise.workout
end

Perhaps you will need to add logic to avoid nilClass errors.

Now you do have @weight.workout through @weight.exercise

Ruby Racer
  • 5,690
  • 1
  • 26
  • 43