Well, I'll post here the solution I found and meet all my needs.
Firstly I created the gem delegate_associations and added it to my project.
The next step was to adjust my migrations:
class CreatePeople < ActiveRecord::Migration
def change
create_table :people do |t|
t.string :name
t.string :cpf_cnpj
t.timestamps
end
end
end
class CreateUsers < ActiveRecord::Migration
def change
create_table :users, id: false do |t|
t.primary_key :person_id
t.string :login
t.string :password
t.timestamps
end
end
end
class CreateSellers < ActiveRecord::Migration
def change
create_table :sellers, id: false do |t|
t.primary_key :person_id
t.decimal :comission, default: 0.0
t.timestamps
end
end
end
Notice that I removed the column id
from User
and Seller
and added the person_id
as the primary key. I did this so that when I associate for example a Seller
to a sale, I will always have the id of Person
which is the same as Seller
.
After that I created 2 Modules:
# app/models/concerns/person_helper.rb
module PersonHelper
extend ActiveSupport::Concern
included do
validates :name, presence: true
end
end
# app/models/concerns/is_a_person.rb
module IsAPerson
extend ActiveSupport::Concern
included do
include PersonHelper
belongs_to :person, autosave: true
delegate_associations to: :person
delegate_attributes to: :person
def self.find_by_id(value)
find_by_person_id(value)
end
def person
super || build_person
end
end
end
My templates are as follows:
# app/models/person.rb
class Person < ActiveRecord::Base
include PersonHelper
has_one :user
accepts_nested_attributes_for :user
has_one :seller
accepts_nested_attributes_for :seller
end
# app/models/user.rb
class User < ActiveRecord::Base
include IsAPerson
validates :login, :password, presence: true
end
# app/models/seller.rb
class Seller < ActiveRecord::Base
include IsAPerson
end
Now all the validations and methods that a person has I will not put directly in the model of Person
and yes in module PersonHelper
so that my User
and my Seller
can also have the same things. / p>
With this I can have for example these possibilities:
> user = User.new(name: 'Nome da pessoa', login: 'admin', password: '123456')
> user.save # true
> user.person.persisted? # true
> user.seller #nil
> user.build_seller # Irá instanciar um Seller e associar com a Person
> user.seller.comission # 0.0
> user.name = 'Joe'
> user.person.name # Joe
Notice that it looks like User
has the name
attribute, and every time I set a new name for user
it automatically moves to person
. This happens by using the gem I made where I use the artifacts from the delegate .
Maybe this is not the most appropriate option, but it has met all my needs and works perfectly.