Auto-relacionamento no Rails/ActiveRecord

Vez ou outra nos deparamos com models que precisam se relacionar com si mesmo e isso é uma prática totalmente possível usando o Active Record. Vamos aprender mais essa?

Pois bem, a técnica é muito simples e vou usar o mesmo exemplo encontrado na própria documentação oficial(https://guides.rubyonrails.org/association_basics.html#self-joins).

A ideia do exemplo é ter uma tabela de empregados e nela mesmo poder indicar quem é o gerente, que nesse caso também será um empregado. Então vamos começar criando uma a aplicação e um scaffold para Empregados.

rails new selfjoinapp
cd selfjoinapp
rails g scaffold Employee name

Prontinho. O próximo passo é alteramos o model Employee indicando o auto-relacionamento.

class Employee < ApplicationRecord
belongs_to :manager, class_name: 'Employee', optional:true
end

Perceba que adicionamos a associação belongs_to indicando ‘manager’, que é um model que não existe, mas na sequência indicamos que a classe que vai controlar essa associação é ‘Emloyee’, que não por acaso é a própria classe, e por fim, adicionamos o optional: true para permitir que os empregados possam ser cadastrados sem a necessidade de indicar um gerente.

Na sequência, precisamos ajustar a migration, indicando que existirá um campo chamado manager e ele terá um índice, sendo assim, internamente será criado como manager_id.

class CreateEmployees < ActiveRecord::Migration[5.2]
def change
create_table :employees do |t|
t.string :name
t.references :manager, index: true
t.timestamps
end
end
end

Agora vamos criar o banco de dados, fazer a migração e já podemos testar.

rails db:create db:migrate
rails console
Employee.create!(name: "Jackson")
=> #<Employee id: 1, name: "Jackson", manager_id: nil, created_at: "2018-12-14 12:24:31", updated_at: "2018-12-14 12:24:31">
my_manager = Employee.first
Employee Load (0.4ms) SELECT "employees".* FROM "employees" ORDER BY "employees"."id" ASC LIMIT ? [["LIMIT", 1]]
=> #<Employee id: 1, name: "Jackson", manager_id: nil, created_at: "2018-12-14 12:24:31", updated_at: "2018-12-14 12:24:31">
employee = Employee.create!(name: "Maria", manager: my_manager)
=> #<Employee id: nil, name: "Maria", manager_id: 1, created_at: nil, updated_at: nil>
employee.name
=> "Maria"
employee.manager.name
=> "Jackson"

Que show, hein! Tudo funcionando como o esperado! 😉

É isso gente! Espero que tenham gostado e caso queiram, o projeto do exemplo acima pode ser encontrado aqui: https://github.com/jacksonpires/selfjoinapp

Aproveitando, não esqueçam de nos seguir nas redes sociais, curtir nossa página no facebook e também se cadastrar me nossa newsletter semanal! 😉

Vlw! Até a próxima!