Rieles 5 - Impedancia de relación de objetos y cómo estructurar múltiples clases / tablas heredadas
EDITAR He editado esto del original para que sea más fácil de entender.
Entiendo el problema de la impedancia de la relación de objeto. Entiendo Rails STI y Polymorphism (la forma de Rails y que no es cierto OO Polymorphism). He leído un montón de blogs y preguntas sobre esto, y todavía no puedo encontrar la respuesta a este problema.
class Person < ApplicationRecord (ie what was ActiveRecord::Base)
end
class Employee < Person
end
class Customer < Person
end
... múltiples otros tipos de Persona
Ahora digamos que el 'cliente' pide extender el sistema y crear algunas cosas nuevas. Llamémoslo Proyecto, al que podemos asignar Empleados:
Ok, creemos un Muchos a Muchos usando la Tercera Forma Normal:
class Project < ApplicationRecord
has_many :assignments
has_many :employees, through: :assignments
end
class Employee < Person
has_many :assignments
has_many :projects, through: :assignments
end
class Assignment < ApplicationRecord
belongs_to :employee
belongs_to :project
end
Esto no funcionara. La migración fallará, ya que no hay una tabla llamada Empleado para crear las restricciones de clave externa. STI significa que la 'clase base' es la tabla People.
DOS PREGUNTAS:
1 ¿Cómo se resuelve esto? (para esto también es posible que desee incluiraquí)
2 ¿Cómo se crean datos serializados correctamente para Proyectos (que deberían incluir empleados, pero no Personas u otros subtipos de Persona)?
ProjectSerializer < ActiveModelSerializers
has_many :employees
has_many :employees, through: :assignments
end
no funcionará, por lo que tendrías que serializar a People.
ACTUALIZAR
En la migración creé tablas de proyectos y tareas (la persona ya existe).
Entonces ahora la base de datos tiene estas tablas:
Project
Person
Assignment
La asignación tiene dos claves foráneas (que hace referencia a Persona, ya que esa es la tabla que existe, no Empleado):
person_id
project_id
Cada vez que intento crear una tarea, se produce este error, que por supuesto esperaba:
ActiveModel::UnknownAttributeError (unknown attribute 'employee_id' for Assignment.)
La solución según la documentación de Rails (sección 4.1.2.5) y cualquier otra respuesta que pueda encontrar en cualquier lugar para esta situación es decirle a Rails cuál es la clave extranjera. Me gusta esto:
class Assignment < ApplicationRecord
belongs_to :employee, foreign_key: "person_id"
belongs_to :project
end
Pero cada ejemplo que encuentro (incluso en la documentación)todos asumen que no hay herencia: todos los modelos heredan de ActiveRecord: Base (o ApplicationRecord en Rails 5).
Aunque explícitamente le digo a Rails que la tabla de asignación tiene una clave extranjera llamada 'person_id' que contiene la identificación del empleado, todavía no puede encontrarla.
Y finalmente probé esto (gracias a la respuesta de @camonz)
class Assignment < ApplicationRecord
belongs_to :person, foreign_key: "person_id", foreign_type: "employee"
belongs_to :project
end
Mismo error.
¿Es realmente una configuración de modelo que Rails no puede manejar?
Aquí está el registro de Rails:
I, [2016-09-22T22:54:55.088466 #12182] INFO -- : Started POST "/assignments" for ::1 at 2016-09-22 22:54:55 +0200
I, [2016-09-22T22:54:55.095768 #12182] INFO -- : Processing by AssignmentsController#create as JSON
I, [2016-09-22T22:54:55.096007 #12182] INFO -- : Parameters: {"data"=>{"attributes"=>{"status"=>"pending"}, "relationships"=>{"project"=>{"data"=>{"type"=>"projects", "id"=>"601"}}, "employee"=>{"data"=>{"type"=>"employees", "id"=>"143"}}}, "type"=>"assignments"}, "assignment"=>{}}
I, [2016-09-22T22:54:55.098032 #12182] INFO -- : {:status=>"pending", :project_id=>"601", :employee_id=>"143"}
I, [2016-09-22T22:54:55.117411 #12182] INFO -- : Completed 500 Internal Server Error in 21ms (ActiveRecord: 8.8ms)
F, [2016-09-22T22:54:55.119116 #12182] FATAL -- :
F, [2016-09-22T22:54:55.119246 #12182] FATAL -- : ActiveModel::UnknownAttributeError (unknown attribute 'employee_id' for Assignment.):
F, [2016-09-22T22:54:55.119283 #12182] FATAL -- :
F, [2016-09-22T22:54:55.119313 #12182] FATAL -- : app/controllers/assignments_controller.rb:18:in `create'