Rails 手册 | 10 - Rails ORM 关联

176 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 29 天,点击查看活动详情

表间关联

绝大多数数据库中不可能只有一张表,而且多张表之间也不是孤立的,通常都存在着一定的联系。例如一个用户只能有一个唯一的 ID,一篇文章中会有很多条评论,一个标签下会有很多文章,一个文章中也会包含很多个标签,在数据库设计的过程中就会考虑这种关系,并为响应的表添加外键和索引。

如果把表与表之间的关系进行抽象概括,两个表之间的关系可以分为3种,一对一关系,一对多关系和多对多关系。

如果第一个表中的每一条数据与第二个表中的0条或者1条数据对应,则属于1对1关联情况,如果第一个表中的1条数据与第二个表中的多条数据对应,而反过来却不成立,则属于1对多关联的情况;如果第一个表中的1条数据与第二个表中的多条数据相对应,反过来第二个表中的1条数据与第一个表中的多条数据对应,则属于多对多的关联。

ActiveRecord 提供了4个方法来表示表与表之间的关联关系:has_one,has_many,belongs_to 和 has_and_belongs_to_many。这四个方法都是以当前模型为基准,指定与其他模型类之间的关系,使用这些方法正确描述表之间的关系后,ActiveRecord 能够自动生成相应的调用方法,大大简化模型类之间的数据操作。

一对一关系

歌词和歌曲是一对一关系,通常一首歌要么没有歌词,要么只对应一篇歌词,使用相应的方法可以定义他们之间的关系,

命令行创建两个模型

rails g model song
rails g model lyric

图片.png

在模型中建立对应的关联关系

# app/models/song.rb
class Song < ApplicationRecord
  has_one :lyric
end
# app/models/lyric.rb
class Lyric < ApplicationRecord
  belongs_to :song
end

定义好类型之间的关联后,他们并不能自动衔接起来,因为 ActiveRecord 不知道使用哪个外键来应用相关联的表,但是如果在创建表时,相关关联字段按照如下图所示的命名约定,那么关联任务就会自动完成了。

一对一关联字段是使用关联表名的单数小写下划线分割加上_id,如下图所示

图片.png

在数据库中创建两个表 songs 和 lyrics,SQL 语句如下:

DROP TABLE IF EXISTS `lyrics`;
CREATE TABLE `lyrics` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `song_id` int(11) NOT NULL,
  `content` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

SET FOREIGN_KEY_CHECKS = 1;

DROP TABLE IF EXISTS `songs`;
CREATE TABLE `songs` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

SET FOREIGN_KEY_CHECKS = 1;

has_one 方法

has_one 的意思是当前对象拥有一个附属对象,它支持如下所示的几个参数: :class_name, 指定关联的类名,在关联名称不符合命名管理时使用 :conditions, 用于指定关联的约束条件 :dependent, 吐过这个参数设置为 destroy,那么当当前记录被删除时,其关联的记录也被删除 :foreign_key, 指定关联的字段名称 :include, 指定加载关联对象时同时要加载的关联对象

has_one :last_comment, :class_name => "Comment", :order => "post_on"
has_one :project_manager, :class_name => "Person", :conditions => "role = 'project_manager'"

启动交互式控制台,创建 Song 数据和 Lyric 数据

图片.png

一旦模型中成功使用了 has_one 方法,模型将会自动获得一些相关方法,这些方法能够大大简化对相关对象的操作。

  • song.lyric: 返回与 song 关联的 lyric 对象,类似于 Lyric.find_by(song.id)

    图片.png

  • song.lyric = lyric: 设置与 song 关联的 Lyric 对象 lyric,类似于 lyric.song_id = song.id

  • song.lyric.nil?: 返回song是否具有关联的 Lyric 对象 图片.png

  • song.build_lyric, 为 song 创建关联的 Lyric 对象,类似于 Lyric.new(song_id: id)

  • song.create_lyric: 为 song 创建关联的 Lyric 对象,类似于 b = Lyric.new(song_id: id); b.save;b
    图片.png