I'm transitioning from "Laravel ORM" to "Rails Active Record" and I couldn't find how do you do something like this:
$this->people()->attach($person['id'], ['role' => $role]);
Explanation for Laravel code snippet
People
is a polymorphic association to the class that is being accessed via $this
via the Role
class. The function above, creates a record in the middle table (roles/peopleables) like this:
id: {{generically defined}}
people_id: $person['id']
role: $role
peopleable_type: $this->type
peopleable_id: $this->id
How the association is defined on the Laravel end:
class XYZ {
...
public function people()
{
return $this->morphToMany(People::class, 'peopleable')->withPivot('role','id');
}
...
}
My efforts in Ruby
Here is how I made the association in Ruby:
class Peopleable < ApplicationRecord
belongs_to :people
belongs_to :peopleable, polymorphic: true
end
class People < ApplicationRecord
has_many :peopleables
end
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
end
I have seen the operation <<
but I don't know if there is any way to set an additional value on the pivot table while triggering this operation. [in this case the roles
or peopleables
tables; I use these two terms interchangeably in this app.]
PS. So, basically the question is how to define additional values on the pivot table in a polymorphic-many association in ActiveRecord and dynamically set those values while initiating an attachment relationship
Our application has a limitless [generally speaking, not that there is no computational limits!] content type: post, novel, poem, etc.
Each of these content types can be associated to individuals who play certain roles: editor, author, translator, etc.
So, for example:
X is the translator of Post#1. X, Y and Z are authors of Post#1.
There is a distinct People
model and each content type has its own unique model [for example: Post
, Poem
, etc].
The idea of :through is referring to the 'Role
class' or 'the pivot table' [whichever way you want to understand it] that the polymorphic association is recorded on it.
In addition to the information regarding a simple polymorphic relationship, there is also the kind of role that is recorded on the pivot table.
For example, X is both the author and the translator for Post#1, so there are two rows with the same people_id
, peopleable_type
and peopleable_id
, however they have different values for role
.
From what I understand given your description, I think you have this models (I'll change the names to what I understand they are, hope it's clear enough):
class Person < ApplicationRecord # using singular for models
has_many :person_roles
end
class Poem < ApplicationRecord
has_many :person_roles, as: :content
end
class Novel < ApplicationRecord
has_many :person_roles, as: :content
end
etc...
class PersonRole < ApplicationRecord
belongs_to :person
belongs_to :content, polymorphic: true
# you should have a "role" column on your table
end
So a Person is associated to a "content" (Novel, Poem, etc) via the join model PersonRole with a specific role. A Person that is the author of some novel and the editor of some peom would have two PersonRole records.
So, if you have a person and you want to assign a new role on some content, you can just do:
person.person_roles.create(role: :author, content: some_poem)
or
PersonRole.create(person: person, role: :author, content: some_poem)
or
some_poem.person_roles.create(person: person, role: :author)
You have two things in play here: "belongs_to :content, polymorphic: true" is covers the part of this being a polymorphic association. Then you have the "PersonRole" table that covers the part you know as "pivot table" (join table/model on rails).
Note that :through
in rails has other meaning, you may want to get all the poems that a user is an author of, you could then have a "has_many :poems, through: :person_roles" association (that won't actually work, it's more complex than that in this case because you have a polymorphic association, you'll need to configure the association with some extra options like source
and scope
for this to work, I'm just using it as an example of what we understand as a has many :through
association).