`

在habtm上使用polymorphic关联

阅读更多
我们知道,在rails中,habtm和polymorphic都是非常好的东东,特别是后者,可以说是rails的ORM中非常强大的功能。《Agile Web Development with Rails》虽然详细讲述了habtm和polymorphic关联,也讲了如何把模型类映射为连接表,但是并没有讲如何把habtm和polymorphic一起使用做一个介绍。这里我就来简单说一下。

还是出自真实项目中的需求,项目是全国大学本科教学评估支持系统,说白了就是大学用来支持本科教学评估的东西。里面有这样一个use case:

评估中需要召开座谈会,参加的人有:专家、教师、学生...(反正就是学校里面的各色人等),并且参加座谈会的各种人都可以是多个。这样就有了这样一个多对多的数据关系:多个人可以参加多个座谈会,参加者的类别是不一样的(需要polymorphic)。

让我们仔细看看这个use case,其实它还是挺微妙有趣的。如果不考虑polymorphic,那么这里显然就是一个标准的habtm关系,那么我们就建立三张表users、symposia和symposia_users,然后两边用habtm关联一下就好了。

但是如果要考虑polymorphic,就没有这么简单了。这里最主要的问题是habtm本身不支持polymorphic选项,支持polymorphic选项的只有belongs_to。那么我们就不得不把habtm拆成has_many和belongs_to两部分了。

先创建关联表attendances及其响应的model:
# create_attendances.rb--------------------------------------
create_table :attendances do |t|
  t.column :attendee_id,   :integer
  t.column :attendee_type, :string
  t.column :symposium_id,  :integer
end
# attendance.rb----------------------------------------------
class Attendance < ActiveRecord::Base
  belongs_to :attendee, :polymorphic => true
  belongs_to :symposium
end

其中的attendee就会多态地关联到专家、教师、学生等人员身上。

然后再配置symposium.rb、expert.rb、teacher.rb、student.rb:
# symposium.rb------------------------------------------------
class Symposium < ActiveRecord::Base
  has_many :attendances
  has_many :experts,
           :through => :attendances,
           [b]:source => :attendee,
           :source_type => 'Expert'[/b]
  has_many :teachers,
           :through => :attendances,
           :source => :attendee,
           :source_type => 'Teacher'
  has_many :students,
           :through => :attendances,
           :source => :attendee,
           :source_type => 'Student'
end
# teacher.rb--------------------------------------------------
class Teacher < ActiveRecord::Base
  has_many :attendances, :as => :attendee
  has_many :symposia, :through => :attendances
end
# expert.rb和student.rb与teacher.rb相同------------------------

以上代码都比较好理解,就是其中的source和source_type选项可能不是很常见,看看ActiveRecord的doc就会明白,source用来指定关联到attendance的哪个属性上(当然就是attendee),而source_type则是在使用了polymorphic的情况下指定attendee的具体类型。

经过以上的配置,整个model的关系就建立起来了,不过在使用这些关系的时候仍需注意一点。假设我们要新建一个座谈会,参与者有专家1、2,教师1、2和学生1、2,代码要怎么写呢?很多人可能都会想是:
symposium = Symposium.new(:name => "座谈会1")
symposium.experts << Expert.find(1) << Expert.find(2)
symposium.teachers << Teacher.find(1) << Teacher.find(2)
symposium.students << Student.find(1) << Student.find(2)
symposium.save

不过这样写是不对的,会得到如下错误:

ActiveRecord::HasManyThroughCantAssociateNewRecords: Cannot associate new records through 'Symposium#attendances' on '#'. Both records must  have an id in order to create the has_many :through record associating them.

意思是说symposium和teacher(expert、student)之间的关联要通过attendance,而现在还没有attendance呢(即both records must have an id)。那么要如何先把要用的attendance创建出来呢?对,在建立关系前先创建并保存symposium,这样就间接地提前创建了需要用的attendance。
begin
  Symposium.transaction do
    symposium = Symposium.new(:name => "座谈会1")
    symposium.save!    [b]# 这句很重要[/b]
    symposium.experts << Expert.find(1) << Expert.find(2)
    symposium.teachers << Teacher.find(1) << Teacher.find(2)
    symposium.students << Student.find(1) << Student.find(2)
    symposium.save!
  end
rescue
  # 处理事务中的异常...
end
分享到:
评论

相关推荐

    cakephp2.2-habtm-example:一个简单的示例(烘焙),展示了如何保存和验证两个模型之间的HABTM关系

    cakephp2.x-habtm-示例cakephp2.x-habtm-example示例说明如何使用CakePHP 2.x保存和验证两个模型之间的HABTM关系(此代码中使用的版本实际上是2.2) 我们使用两种模型:Post和Tag。 一个帖子与N个标签相关,一个标签...

    node-v12.14.0-darwin-x64.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    基于使用microPython的开发单片机设计源码.zip

    我们在单片机开发中常会遇到需要将UTF-8转换为GBK编码的需求。在了解各种编码格式的情况下可知, UFT-8不能直接转成GBK,需中转成unicode再转换为gbk。而unicode和gbk之间没有算法可以直接计算,需要查表方式获取。 网上有一些C语言实现的代码,我这里分享一种microPython的实现代码 接下来就是要考虑表的存储方式了,刚开始我想着把表存到代码里直接通过索引实现编码转换。但是gb2312有七千多个字符全部存储要耗费很大内存,即使是32位的esp32也只有512k的内存,加上其他资源的消耗,剩余的内存不足以存储编码转换表。 于是只能将表保存成一个文件(转化成bin文件会比较好,方法类似),通过读写文件来减少内存开销。 具体的查表就是简单的二分法

    基于VB实现的车队综合业务管理系统(论文+源代码)

    基于VB实现的车队综合业务管理系统(论文+源代码) 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。

    基于知识图谱的推荐算法-NCFG的实现python源码+运行说明.zip

    基于知识图谱的推荐算法-NCFG的实现 运行环境 python == 3.7.0 torch == 1.12.0 pandas == 1.1.5 numpy == 1.21.6 sklearn == 0.0 数据集介绍 music-音乐 book-书籍 ml-电影 yelp-商户 文件介绍 ratings.txt:记录用户点击的项目,1代表点击了,0代表没有点击 kg.txt:知识图谱文件,第一列是头实体,第二列是尾实体,第三列是关系 user-list.txt:用户及其id文件,第一列是用户的id,第二列是用户 其余文件可忽略

    JAVA002打飞机游戏设计(程序+设计说明书).zip

    JAVA002打飞机游戏设计(程序+设计说明书).zip

    Engineering-Electromagnetic-Theory-Lab-3.pdf

    Engineering_Electromagnetic_Theory_Lab_3.pdf

    自己弄的基于matlab实现的多端直流配电网的仿真模型,是支撑自己小论文的东东 仿真环境是用的matlab

    自己弄的基于matlab实现的多端直流配电网的仿真模型,是支撑自己小论文的东东。仿真环境是用的matlab。

    BBR、A2O、MBR工艺比选.doc

    课程设计,污水处理设计方案

    DHT11温湿度传感器是一款高性能、低成本的数字温湿度复合传感器 它集成了温度感应和湿度感应功能,可以准确地测量环境中的温度和湿

    DHT11温湿度传感器是一款高性能、低成本的数字温湿度复合传感器。它集成了温度感应和湿度感应功能,可以准确地测量环境中的温度和湿度,并通过数字信号输出数据。以下是关于DHT11温湿度传感器的详细介绍: DHT11传感器内部包含一个NTC热敏电阻用于温度测量和一个薄膜电容湿度传感材料用于湿度测量。NTC热敏电阻的电阻值会随着温度的变化而变化,DHT11通过测量电阻值的变化来计算环境的温度。而薄膜电容湿度传感材料的电容值则会随着湿度的变化而变化,DHT11通过测量电容值的变化来计算环境的湿度。 DHT11传感器具有高精度、高可靠性和稳定性好的特点。其湿度测量范围为20%RH至90%RH,精度可达±5%RH;温度测量范围为-20℃至+60℃,精度可达±2℃。传感器的工作电压范围为3.3V至5.5V,工作电流较小,功耗低。此外,DHT11传感器还具有超长的信号传输距离和超强的抗干扰能力,可以在复杂的环境中稳定工作。 DHT11传感器采用单总线数字信号传输方式,通过单个引脚进行数据输入和输出。它使用特定的时序信号来传输温度和湿度数据,主机可以通过解析这些时序信号来获取温度和湿度的数值。这种

    某钢厂转炉浊环供水泵站给排水竣工图.zip

    污水处理

    delphi家庭财务管理系统.zip

    delphi家庭财务管理系统.zip

    node-v10.23.2-linux-arm64.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    ASP+ACCESS网上人才信息管理系统(源代码+设计说明书).zip

    ASP+ACCESS网上人才信息管理系统(源代码+设计说明书).zip

    ASP基于BS结构的工厂设备管理系统的设计与开发(源代码+设计说明书).zip

    ASP基于BS结构的工厂设备管理系统的设计与开发(源代码+设计说明书).zip

    node-v10.23.3-linux-arm64.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    埃森哲_组织设计的指导思想gl.ppt

    埃森哲_组织设计的指导思想gl.ppt

    卷积神经网络(Convolutional Neural Networks,CNN)是深度学习领域中一种非常重要的神经网络结构,特

    卷积神经网络(Convolutional Neural Networks,CNN)是深度学习领域中一种非常重要的神经网络结构,特别适用于处理图像和视频数据。以下是关于卷积神经网络的500字资源介绍: 卷积神经网络是一类包含卷积计算的前馈神经网络,它的核心在于“卷积与池化”操作。在卷积层中,神经元仅与部分邻层神经元连接,这种局部连接和权值共享的特性使得卷积神经网络能够以较小的计算量学习格点化特征,如像素和音频,且稳定有效。 卷积神经网络的主要构成包括卷积层、池化层和全连接层。卷积层通过卷积核对输入图像进行特征提取,生成特征图;池化层则对特征图进行下采样,降低数据维度,同时保留重要信息;全连接层则负责将提取的特征进行整合,用于分类或回归任务。 卷积神经网络在计算机视觉领域具有广泛的应用,如图像分类、目标检测、人脸识别等。通过训练大量的图像数据,卷积神经网络能够自动学习图像的特征表示,比传统的手工设计特征方法更加有效。此外,卷积神经网络也被应用于自然语言处理、语音识别等领域,并取得了显著的成果。 总之,卷积神经网络是一种强大的深度学习模型,它通过模拟人类的视觉系统来处理图像和视频数据

    基于VB+access实现的小区物业管理系统(系统+论文).zip

    基于VB+access实现的小区物业管理系统(系统+论文) 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。

    基于matlab实现的用于边角网平差,可实现平差、误差椭圆绘制、成果坐标输出等 内附参考观测数据.rar

    基于matlab实现的用于边角网平差,可实现平差、误差椭圆绘制、成果坐标输出等 内附参考观测数据.rar

Global site tag (gtag.js) - Google Analytics