anger
anger

Reputation: 1018

Rails ActiveRecord belongs_to association not loading

I am trying to render a list of Active Records as follows:

<% @workout_sets.each do |workout_set| %>
  <tr>
    <td><%= workout_set.reps %></td>
    <td><%= workout_set.exercise.name %></td>
    <td><%= link_to 'Show', workout_set %></td>
    <td><%= link_to 'Edit', edit_workout_set_path(workout_set) %></td>
    <td><%= link_to 'Destroy', workout_set, method: :delete, data: { confirm: 'Are you sure?' } %></td>
  </tr>
<% end %>

My AR setup looks like:

class WorkoutSet < ActiveRecord::Base
  belongs_to :workout
  belongs_to :exercise, class_name: 'Exercise', foreign_key: 'exercises_id'
end

class Exercise < ActiveRecord::Base
end

class Workout < ActiveRecord::Base
  has_many :workout_set
end

and my schema is

create_table "exercises", force: :cascade do |t|
  t.string   "name",       null: false
  t.datetime "created_at", null: false
  t.datetime "updated_at", null: false
end

add_index "exercises", ["name"], name: "index_exercises_on_name", unique: true

create_table "workout_sets", force: :cascade do |t|
  t.integer  "reps",         null: false
  t.datetime "created_at",   null: false
  t.datetime "updated_at",   null: false
  t.integer  "exercises_id"
 t.integer  "workouts_id"
end

add_index "workout_sets", ["exercises_id"], name: "index_workout_sets_on_exercises_id"
add_index "workout_sets", ["workouts_id"], name: "index_workout_sets_on_workouts_id"

create_table "workouts", force: :cascade do |t|
  t.string   "location",   null: false
  t.datetime "created_at", null: false
  t.datetime "updated_at", null: false
end

In attempting to render the page I get the following error

undefined method `name' for nil:NilClass

When I change the path in my template to <%= workout_set.exercise %> it renders each row like 444 #<Exercise:0x007fbde9dde998> Show Edit Destroy which is what I expect.

Why is the the attempted access of the name property causing this error?

Upvotes: 3

Views: 768

Answers (2)

SomeSchmo
SomeSchmo

Reputation: 665

You haven't set up the relationship in the Exercise model

class Exercise < ActiveRecord::Base
  has_many :workout_sets
  has_many :workouts, through: :workouts_sets #not needed but good to setup
end

or if you're trying to do a 1-to-1 relationship between Exercise and WorkoutSet

class Exercise < ActiveRecord::Base
  has_one :workout_set
end

Also having an 's' at the end of the foreign keys in your workout_sets table (i.e. 'workouts_id') is somewhat bad form. I'm pretty sure Rails will be smart enough to make it work but if you run into more bugs I'd try changing those to 'workout_id' and 'exercise_id'.

Upvotes: 0

James Klein
James Klein

Reputation: 612

One of your WorkoutSet does not have an associated Exercise. You can enforce that a WorkoutSet has an exercise Exercise in your WorkoutSet model but there are implications to that. Mainly, you could not create a WorkoutSet without first creating the Exercise. If that's what you want then add the following to the WorkoutSet model.

validates_presence_of :exercise_id

More likely though, you just want to handle the page crashing when there is no associated Exercise.

<td><%= workout_set.exercise.name unless workout_set.exercise.blank?  %></td>

That will give you a blank cell but you can do something like this to have a placeholder.

<td><%= workout_set.exercise.blank? ? "No exercise for this set" : workout_set.exercise.name %></td>

Upvotes: 2

Related Questions