更改用户表中的字段after_create记录满足条件

时间:2013-05-20 20:43:22

标签: ruby-on-rails ruby model-view-controller

我想在完成锻炼后更改Users表中的用户workout_id。我无法弄清楚如何做到这一点。以下是我试图弄清楚的两种方法。

尝试1:在控制器中放置一个if语句,当true为增量时,用户workout_id - 问题是if语句只在​​条件已经为真时才通过,所以用户需要尝试在锻炼结束后完成额外的锻炼。

示例:

def create
    @completed_set = CompletedSet.new(params[:completed_set])

    if @totalExercisesInWorkout.included_in?(@completedExercises) == true
      raise "it worked!"
    end

    respond_to do |format|
      if @completed_set.save
        format.html { redirect_to profile_path, notice: 'Successfully completed set.' }
        format.json { render json: @completed_set, status: :created, location: @completed_set }
      else
        format.html { render action: "new" }
        format.json { render json: @completed_set.errors, status: :unprocessable_entity }
      end
    end
  end

尝试2 使用模型中的after_save回调。 - 这不起作用,因为我无法访问模型中的会话信息,因此我无法知道用户是什么,他们的workout_id是什么,以及他们是否已完成锻炼。

这个问题必须有一个简单的解决方案,但我完全难过!

谢谢!

编辑:

当具有锻炼的exercise_id的数组与用户的completed_set exercise_is的数组匹配时,锻炼完成。因此,当以下代码为真时:

@totalExercisesInWorkout.included_in?(@completedExercises)

.include_in?是Array Class的扩展,如果第二个数组包含第一个数组中的所有值,则返回true。

锻炼has_many练习 当用户“完成”锻炼时,该锻炼和相关信息(例如user_id,workout_id等)存储在completed_set表中。

在我的application_controller我有一个initialize_vars方法,可以找到我需要了解的有关用户及其锻炼的所有信息。这是:

def initialize_vars
    @workout = Workout.find(current_user.workout_id)
    @user_program = current_user.program
    @user_cycle = Cycle.find(current_user.cycle_id)
    @user_group = Group.find(current_user.group_id)

    @exercise = @workout.exercises
    @workout_exercise = @workout.workout_exercises

    # Array needs to have an exercise for every set in the exercise
    @exercisesInWorkout = @workout.exercises.pluck(:exercise_id)
    # Array of the sets in the users current workout
    @workoutSets = @workout_exercise.pluck(:sets)
    # Array of exercises user has completed in current workout
    @completedExercises = CompletedSet.where(:user_id => current_user.id).pluck(:exercise_id) 
    # Array of exercise_id's in workout times the number of sets for each exercise
    @totalExercisesInWorkout = @exercisesInWorkout.zip(@workoutSets).map { |n1, n2| [n1] * n2 }.flatten

    #Total number of reps a user has completed
    @repsCompleted = CompletedSet.where(:user_id => current_user.id).pluck(:repetitions).sum

    #Total amount of weight a user has lifted
    @weightLifted = CompletedSet.where(:user_id => current_user.id).pluck(:weight).sum
  end

编辑2:

我在这里学到了很多东西。我重构了我的代码。这就是现在的样子。

Class User

def cycle
    Cycle.find(cycle_id)
  end

  def group
    Group.find(group_id)
  end

  def workout
    Workout.find(workout_id)
  end

  def completed_exercise_ids_array(user)
    CompletedSet.where(workout_id: workout_id, user_id: user).pluck(:exercise_id)
  end

  def sets_in_workout_array
    workout.workout_exercises.pluck(:sets)
  end

  def exercises_in_workout_times_sets_array
    workout.workout_exercises.pluck(:exercise_id).zip(sets_in_workout_array).map { |n1, n2| [n1] * n2 }.flatten
  end

  def update_workout_if_needed!
    if exercises_in_workout_times_sets_array.included_in?(completed_exercise_ids_array)
      self.workout.id = self.workout.next_workout_id
      save!
    end
  end

# Methods for progress area
  def total_reps_completed(user)
    CompletedSet.where(user_id: user).sum(:repetitions)
  end

  def total_weight_lifted(user)
    CompletedSet.where(user_id: user).sum(:weight)
  end

我的application_controller

class ApplicationController 

# Application wide instance variables go here. Just don't forget to call initialize_vars in the controllers you want to call these variables in.
  def initialize_vars
    @user_workout = current_user.workout
    @user_cycle = current_user.cycle
    @user_group = current_user.group

    @exercise = @user_workout.exercises

    # Array of the sets in the users current workout
    @workoutSets = current_user.sets_in_workout_array

    # Array of exercises user has completed in current workout
    @completedExercises = current_user.completed_exercise_ids_array(current_user) 

    # Array of exercise_id's in workout times the number of sets for each exercise
    @totalExercisesInWorkout = current_user.exercises_in_workout_times_sets_array

  end

我将一些逻辑移到了profile_controller

1 个答案:

答案 0 :(得分:1)

对于CompletedSet的after_create回调将是最佳选择:

class CompletedSet < ActiveRecord::Base
  belongs_to :user
  belongs_to :workout
  belongs_to :exercise

  after_create :update_user_workout

  def update_user_workout
    user.update_workout_if_needed!
  end
end

class User < ActiveRecord::Base
  has_many :completed_sets
  belongs_to :workout

  def completed_exercise_ids
    completed_sets.where(workout_id: workout_id).pluck(:exercise_id)
  end

  def update_workout_if_needed!
    if completed_exercise_ids.included_in?(workout.workout_exercises.pluck(:exercise_id))
      self.workout = Workout.next(workout)
      save!
    end
  end
end

class Workout < ActiveRecord::Base
  has_many :workout_exercises
  has_many :exercises, through: :workout_exercises

  # some logic to determine the next workout - modify as needed
  def self.next(workout)
    where("workouts.sequence > ?", workout.sequence).order(:sequence).first
  end
end

此解决方案假设您已将current_user与控制器create操作中的CompletedSet相关联(我没有看到):

def create
  @completed_set = current_user.completed_sets.build(params[:completed_set])
  ...