Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

rails model has_many :through associations

I am trying to get my relationships worked out but I am having trouble using the associations.

So I have three models Workout, Exercise and WorkoutExercise. A workout should have many exercises and a exercise should have different workouts therefore I wrote:

class Workout < ActiveRecord::Base
  has_many :workout_exercises
  has_many :exercises, :through => :workout_exercises
end

class Exercise < ActiveRecord::Base
  has_many :workout_exercises
  has_many :workouts, :through => :workout_exercises
end

class WorkoutExercise < ActiveRecord::Base
  belongs_to :exercise
  belongs_to :workout
end

I am running some tests but the tests aren't passing once I create a workout, exercise and then join them in the workout_exercise class. It won't let me access the exercises in the workout like this:

Workout.create
Exercise.create
WorkoutExercise.create(:workout => Workout.first, :exercise => Exercise.first)
work = Workout.first
work.exercises.count #This line causes the error: undefined method exercises

My database tables look like this:

class CreateWorkouts < ActiveRecord::Migration
  def change
    create_table :workouts do |t|
      t.string :title
      t.text :description
      t.float :score
      t.timestamps
    end
  end
end 

class CreateExercises < ActiveRecord::Migration
  def change
    create_table :exercises do |t|
      t.string :title
      t.text :description
      t.float :value
      t.timestamps
    end
  end
end

class CreateWorkoutExercises < ActiveRecord::Migration
  def change
    create_table :workout_exercises do |t|
      t.timestamps
    end
  end
end

When I run this tests it says exercises is undefined. Does anyone have any ideas?

like image 410
trev9065 Avatar asked Mar 10 '12 01:03

trev9065


People also ask

How is polymorphic association set up in Rails?

The basic structure of a polymorphic association (PA)sets up 2 columns in the comment table. (This is different from a typical one-to-many association, where we'd only need one column that references the id's of the model it belongs to). For a PA, the first column we need to create is for the selected model.


1 Answers

Ok, so your WorkoutExercises table can't be empty. This is how it should look:

class CreateWorkoutExercises < ActiveRecord::Migration
  def change
    create_table :WorkoutExercises do |t|
      t.integer :exercise_id, :null => false
      t.integer :workout_id, :null => false

      t.timestamps
    end

    # I only added theses indexes so theoretically your database queries are faster.
    # If you don't plan on having many records, you can leave these 2 lines out.
    add_index :WorkoutExercises, :exercise_id
    add_index :WorkoutExercises, :workout_id
  end
end

Also, you can name this table whatever you'd like, it doesn't have to be WorkoutExercises. However, if you were using a has_and_belongs_to_many relationship, your table would have to mandatorily be named ExercisesWorkout. Notice how Exercises comes before Workout. The names have to be alphabetically ordered. Don't ask me why, it's just a Rails convention.

So, in this case, you'll do fine with your table being named WorkoutExercises. But if I were you, I'd change it to ExercisesWorkout, just in case, so that you never get it wrong.

like image 88
Ashitaka Avatar answered Oct 07 '22 00:10

Ashitaka