Rails 5-对象关系阻抗以及如何构造多个继承的类/表 [英] Rails 5 - Object Relation Impedence and how to structure multiple inherited classes/tables

查看:103
本文介绍了Rails 5-对象关系阻抗以及如何构造多个继承的类/表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

编辑 我已经对原始内容进行了编辑,以使其更易于理解.

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您如何解决此问题? (为此,您可能还想加入

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'

推荐答案

  1. 在迁移时,将FK约束放在addressses表上.在子类上,重新定义has_many关系并指定:foreign_key& :foreign_type.
  2. 在工作分配序列化器上,指定belongs_to :employee,AMS应该正确处理它.

  1. On the migration, drop the FK constraints on the addressses table. On the child classes redefine the has_many relation and specify :foreign_key & :foreign_type.
  2. 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆