I'm experiencing some issues when trying to add a has_one relation to existing model. I ran
rails g migration AddPracticeToLesson practice:references
and generated the following migration
class AddPracticeToLesson < ActiveRecord::Migration[7.0]
def change
add_reference :lessons, :practice, null: true, foreign_key: true
end
end
and I have the lesson model as
class Lesson < ApplicationRecord
extend FriendlyId
friendly_id :title, use: :slugged
acts_as_list
belongs_to :course
has_many :sections, -> { order(position: :asc) }, as: :sectionable, dependent: :destroy
has_one :quiz, through: :sections
has_one :practice # ADDED THIS
has_one_attached :cover_image
end
to which I added the line has_one :practice
. I also added belongs_to :lesson, optional: true
for the practice model which now looks like
class Practice < ApplicationRecord
extend FriendlyId
friendly_id :title, use: :slugged
enum status: [:unpublished, :published]
has_many :sections, -> { order(position: :asc) }, as: :sectionable, dependent: :destroy
has_one :quiz, through: :sections
has_one_attached :cover_image
belongs_to :lesson, optional: true
end
but now upon running @lesson.practice
will result in an error stating
PG::UndefinedColumn: ERROR: column practices.lesson_id does not exist
which I don't understand. Why is it trying to access practices.lesson_id and not just find the practice with the lesson.practice_id?
CodePudding user response:
The problem is most likely that you have defined the reference on the wrong table.
From https://guides.rubyonrails.org/v7.0/association_basics.html#the-has-one-association:
A has_one association indicates that one other model has a reference to this model. That model can be fetched through this association.
What this means in practice is that your table practice
(or practices
whichever is the real table name) should have a reference to lessons
.
In your migration, change
add_reference :lessons, :practice, null: true, foreign_key: true
to
add_reference :practice, :lessons, null: true, foreign_key: true
If you want to use the Rails generators,
rails g migration AddLessonRefToPractices lesson:references
seemed to create the correct migration
class AddLessonRefToPractices < ActiveRecord::Migration[7.0]
def change
add_reference :practices, :lesson, foreign_key: true
end
end
I took the naming convention for the migration from https://guides.rubyonrails.org/v7.0/active_record_migrations.html#creating-a-standalone-migration (scroll down to where they define the AddUserRefToProducts migration, almost until section 2.2).
Naming the migration matters, at least in some cases, as Rails tries to conclude from the name and given attributes what you want to do.
Put another way, whenever you use the association belongs_to
the reference field must always be defined in that table (https://guides.rubyonrails.org/v7.0/association_basics.html#the-belongs-to-association). As your Practice
model defines belongs_to :lesson
, the reference field must be defined in the table for Practice
.