Setting up Rails has-many-through association

72 Views Asked by At

I have four models:

  • User
  • Exercise
  • Result
  • UsersExercise

I am trying to build an association between the models which allows me to make ORM statements like:

User.first.exercises.first.barbell_push

What I want to get is every exercise for User, then get a barbell_push result.

Below are my current models and associations:


UsersExercise

Table:

create_table :users_exercises do |t|
  t.integer :user_id
  t.integer :exercise_id
  t.date :date
  t.timestamps null: false
end

Model:

class UsersExercise < ActiveRecord::Base
  belongs_to :user
  belongs_to :exercise
end

Exercise

Table:

create_table :exercises do |t|
  t.integer :dead_lift_id
  t.integer :barbel_push_id
  t.integer :dumbbels_curl_id
  t.timestamps null: false
end

Model:

class Exercise < ActiveRecord::Base
  has_many :dead_lift, class_name: 'Result', foreign_key: 'exercise_id'
  has_many :barbel_push, class_name: 'Result', foreign_key: 'exercise_id'
  has_many :dumbbell_curl, class_name: 'Result', foreign_key: 'exercise_id'
  has_many :users_exercises, dependent: :destroy
  has_many :users, through: :users_exercises
end

Result

Table:

create_table :results do |t|
  t.integer :reps
  t.integer :weight
  t.integer :exercise_id
  t.timestamps null: false
end

Model:

class Result < ActiveRecord::Base
  belongs_to :exercise
end

User

Model:

class User < ActiveRecord::Base
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable, :recoverable, :rememberable,
         :trackable, :validatable, :confirmable, :omniauthable, :omniauth_providers => [:google_oauth2]
  ROLES = [:admin, :user, :trainer, :dietician]
  has_many :sent_messages, :class_name => "Message", :foreign_key => "sender_id"
  has_many :received_messages, :class_name => "Message", :foreign_key => "receiver_id"
  has_many :users_exercises
  has_many :exercise, through: :users_exercises
end
1

There are 1 best solutions below

1
On BEST ANSWER

I think you need only one table for this (you already have :users)

create_table :exercises do |t|
  t.integer :user_id
  t.string :name
  t.integer :weight
  t.integer :reps
  t.date :check_in_time
  t.date :check_out_time
  t.timestamps null: false
 end

The "name" column would be barbell_push, dumbell_curl, etc, gotten from a collection field in your form. This would require check_in and check_out when moving from one exercise to the other, but that should be very simple. With this you could indeed get:

@user.barbell_push.date
@user.barbell_push.duration (time elapsed from check-in to check-out)
@user.barbell_push.reps
@user.barbell_push.weight
@user.dumbell_curl.reps
etc in whatever sequence you want to present the data.