Reputation: 600
I'm having a problem when I try to access relationships or attributes of my models. I have the following code:
class Occupation < ApplicationRecord
belongs_to :user
belongs_to :occupationable, polymorphic: true
end
A user can have multiple occupations and these occupations have specific relationships and attributes.
class User < ApplicationRecord
has_many :occupations, dependent: :destroy
end
class Teacher < ApplicationRecord
has_one :occupation, as: :occupationable
end
class Psychologist < ApplicationRecord
has_one :occupation, as: :occupationable
end
class Parent < ApplicationRecord
has_one :occupation, as: :occupationable
has_many :children
end
The problem occurs in the Parent classes. A parent can have multiple children, but how can I access these children?
I tried the following but unsuccessfully:
ID | OCCUPATIONABLE_ID | OCCUPATIONABLE_TYPE | USER_ID | CREATED_AT | UPDATED_AT
---|-------------------|---------------------|---------|-------------------------|-------------------------
1 | 1 | Parent | 1 | 2018-07-26 13:49:06 | 2018-07-26 13:49:06
User.find(1).occupations.where(occupationable_type: "Parent").children
NoMethodError (undefined method `children' for Occupation::ActiveRecord_AssociationRelation:0x0000559d4c601898
Upvotes: 0
Views: 255
Reputation: 20263
User.find(1).occupations.where(occupationable_type: "Parent").children
As indicated by the error, returns an ActiveRecord_AssociationRelation
which does not have the method children
.
If you do:
User.find(1).occupations.find_by(occupationable_type: "Parent")
That will return a single occupation
record. But, you don't want the occupation
, you want the Parent
. So, try:
User.
find(1).
occupations.
find_by(occupationable_type: "Parent").
occupationable.
children
But, if that user
doesn't have an occupation
with occupation_type
"Parent", then you're going to get some errors (because you'll try to call occupationable
on a nil
object).
So, you could try:
User.
find(1).
occupations.
find_by(occupationable_type: "Parent")&.
occupationable&.
children
I don't know where you're using that code. But wherever it is, you need to know a lot about how your models are set up. You might consider going for some encapsulation. Something, perhaps, like:
class User < ApplicationRecord
has_many :occupations, dependent: :destroy
def occupation(type)
occupations.
find_by(occupationable_type: type)&.
occupationable
end
def children
occupation('Parent')&.children
end
end
In which case you could do something like:
User.find(1).children
And now you don't need to know anything about how your models are set up in order to find the children.
Down the road, I imagine you might end up doing something like:
class Teacher < ApplicationRecord
has_one :occupation, as: :occupationable
has_many :students
end
In which case, you might do:
class User < ApplicationRecord
has_many :occupations, dependent: :destroy
def occupation(type)
occupations.
find_by(occupationable_type: type)&.
occupationable
end
def children
occupation('Parent')&.children
end
def students
occupation('Teacher')&.students
end
end
You're going to end up with redundancy (maybe a lot). And, it might get tricky when you go to find all the Teachers
for a Student
or Parents
for a Child
. But, that's a whole other kettle of fish.
Upvotes: 1