I've been trying to find a solution for 2 days came up with nothing yet.
I have a model called Course
that has the following columns:
create_table :courses do |c|
c.integer :member_limit
c.string :color
c.float :rating
c.timestamps
end
I also have a Content
model that has columns that Course
benefits from but also benefits other models in my database, such as:
create_table :contents do |c|
c.references :contentable, polymorphic: true, index: true
c.string :title
c.text :description
c.text :script
c.string :cover
c.string :media_type
...
c.integer :creator_id, index: true, foreign_key: :user_id
end
I can't set Course < Content
because I will lose the columns that Course has internally such as member_limit
and so on, so I went with Polymorphic. However, I want to avoid having to call course.content.title
and just write course.title
but also access course.member_limit
the same way and save both those fields by using course.save
.
What do you recommend the best approach to be?
current structure.
Course:
class Course < ApplicationRecord
has_one :content, as: :contentable, dependent: :destroy
after_initialize :init
def init
if self.new_record?
self.content ||= build_content
end
end
end
Content:
class Content < ApplicationRecord
belongs_to :creator, optional: true, class_name: 'User'
end
I think your premise is wrong in the sense that what you want to do should not be done. I explain:
What you want, can be done via helper methods like so:
class Course < AR
def title
content.title
end
end
Which is ugly, violates every coding argument ever written, and its just bad practice. But, apart for some meta magic that could avoid having to write the helper methods one by one (notice i said write, because ultimately, they would be implemented), the end result would have to be this way. There is no other way to do it. SO my answer, don't do this.
Understanding polymorphism is not easy. Its easy to implement but difficult to know when. You want an abstract box that contains the columns of several other resources just because. You give no reasoning behind the decision of creating "...a Content model that has columns that Course benefits from but also benefits other models in my database". I ask. why? whats the benefit? why do this? Is it working as well as expected? is it easier to use and extend? is it encapsulated? Is it dry, rest, solid, and every other acronym used these days?
The short answer is NO. It isn't. So don't do it. Have the Course class have title. If another table also has title, so what? Do you know how many tables in the world have the column "name"? If we all wanted to implement it your way we would have something like this:
class School < Ar
belongs_to :name
def full_name
name.body
end
end
class Student < Ar
belongs_to :name
def full_name
name.body
end
end
which is clearly not useful. So if it is not useful for one column, why does it become useful for more columns?
Conclusion:
In STI, The Content table would have had ALL the columns of Course PLUS ALL the columns of any other table that wanted to be a course. This is good practice for resources that essentially, in data are the same or almost (seems a lot what you describe) and you don't want to repeat code in all children classes. All STI can be implemented without STI by repeating the parent class code in each child class.
So, short answer (a bit late no?). No, you can't do what you want. You can either
def title=
. Are you gonna re-implement all of them?Sorry for the length, just seen this mistake too many times.