Rails 5-对象关系阻抗以及如何构造多个继承的类/表 [英] Rails 5 - Object Relation Impedence and how to structure multiple inherited classes/tables
问题描述
编辑 我已经对原始内容进行了编辑,以使其更易于理解.
EDIT I have edited this from the original to make it easier to understand.
我了解对象关系阻抗问题.我了解Rails STI和多态性(Rails的方式,它不是真正的OO多态性).我已经阅读了很多博客和与此相关的问题,但仍然找不到该问题的答案.
I understand the Object Relationship Impedance problem. I understand Rails STI and Polymorphism (the Rails way and that it's not true OO Polymorphism). I've read a TON of blogs and questions on this, and still cannot find the answer to this problem.
class Person < ApplicationRecord (ie what was ActiveRecord::Base)
end
class Employee < Person
end
class Customer < Person
end
...其他多种人
现在,可以说客户"要求扩展系统并创建一些新内容.我们称之为项目,我们可以为其分配员工:
Now lets say the 'client' asks to extend the system, and create some new stuff. Let's call it a Project, to which we can assign Employees:
好吧,让我们使用第三范式创建一个多对多:
Ok so let's create a Many-to-Many using Third Normal Form:
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
这行不通.迁移将失败,因为没有名为Employee的表可在其上创建外键约束. STI表示基类"是People表.
This won't work. The migration will fail, since there is no table called Employee to create the foreign-key constraints on. STI means that the 'base class' is the People table.
两个问题:
1 How do you solve this? (for this you may also want to chip in here)
2如何为Projects(应该包括员工,但不包括People或Person的其他子类型)正确创建序列化数据?
2 How do you create serialised data properly for Projects (which should include employees, but not People or other sub-types of Person)?
ProjectSerializer < ActiveModelSerializers
has_many :employees
has_many :employees, through: :assignments
end
将无法正常工作,因此您必须序列化People.
won't work, so you would have to serialise People.
更新
在迁移中,我创建了Project和Assignment表(人员已经存在).
In the migration I created Project and Assignment tables (Person already exists).
所以现在数据库具有这些表:
So now the database has these tables:
Project
Person
Assignment
工作分配具有两个外键(引用Person,因为那是存在的表,而不是Employee):
Assignment has two foreign keys (referencing Person, since that is the table that exists, not Employee):
person_id
project_id
每次尝试创建分配时,都会引发此错误,这当然是我所期望的:
Every time I try to create an assignment, this error is thrown, which I expected of course:
ActiveModel::UnknownAttributeError (unknown attribute 'employee_id' for Assignment.)
根据Rails文档的解决方案(第4.1.2.5节)和在这种情况下,我在任何地方都能找到的所有其他答案就是告诉Rails什么是foreign_key.像这样:
The solution according to Rails documentation (section 4.1.2.5) and every other answer I can find anywhere for this situation is to tell Rails what the foreign_key is. Like this:
class Assignment < ApplicationRecord
belongs_to :employee, foreign_key: "person_id"
belongs_to :project
end
但是我发现的每个示例(甚至在文档中)都都假设没有继承-所有模型都继承自ActiveRecord:Base(或Rails 5中的ApplicationRecord).
But every example I find (even in the documentation) all assume that there is no inheritance - all the models are inheriting from ActiveRecord:Base (or ApplicationRecord in Rails 5).
即使我明确地告诉Rails分配表有一个名为'person_id'的外键,其中包含员工的ID,但仍然找不到它.
Even though I am explicitly telling Rails that the assignment table has a foreign_key called 'person_id' that holds the id for the employee, it still cannot find it.
最后我尝试了这个(由于@camonz的回答)
And finally I tried this (thanks to the answer from @camonz)
class Assignment < ApplicationRecord
belongs_to :person, foreign_key: "person_id", foreign_type: "employee"
belongs_to :project
end
相同的错误.
这真的是Rails无法处理的模型设置吗?
这是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'
推荐答案
- 在迁移时,将FK约束放在
addressses
表上.在子类上,重新定义has_many
关系并指定:foreign_key
&:foreign_type
. -
在工作分配序列化器上,指定
belongs_to :employee
,AMS应该正确处理它.
- On the migration, drop the FK constraints on the
addressses
table. On the child classes redefine thehas_many
relation and specify:foreign_key
&:foreign_type
. On your Assignment serializer, specify the
belongs_to :employee
, AMS should handle it correctly.
还要查看has_many
关联的:source
和:source_type
选项.
Also take a look at the :source
and :source_type
options of the has_many
association.
这篇关于Rails 5-对象关系阻抗以及如何构造多个继承的类/表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!