Rails 手册 | 11 - Rails ORM 关联

127 阅读3分钟

表间关联 - 一对多和多对多

一对多

一对多关系有很多种,比如一篇文章会包含多个评论,而一个评论只能属于一个文章,文章和评论之间通过评论表中的文章 id 来实现关联,如下图所示:

图片.png

通常项目(Project)和 任务(Task)是一对多关联的,一个项目中包含多个任务,而每个任务只能属于一个项目

使用命令行创建两个模型 Project 和 Task

rails g model project
rails g model task

图片.png

Rails 中一对多关系要分别在“一”的模型中使用 has_many,在“多”的模型中使用 belogs_to 来建立这种一对多的关系,建立 Project 和 Task 的一对多关系,具体代码如下所示:

class Project < ApplicationRecord
  has_many :tasks
end
class Task < ApplicationRecord
  belongs_to :project
end

修改 Task 模型和 Project 模型的迁移文件

class CreateTasks < ActiveRecord::Migration[7.0]
  def change
    create_table :tasks do |t|
      t.string :task_name
      t.references :project, foreign_key: {to_table: :projects}, index: true
      t.timestamps
    end
  end
end
class CreateProjects < ActiveRecord::Migration[7.0]
  def change
    create_table :projects do |t|
      t.string :project_name
      t.timestamps
    end
  end
end

执行迁移命令 rails db:migrate 即可在数据库中创建 tasks 和 projects 两张表,并且自动在 task 表中创建了外键引用

图片.png

has_many 方法

has_many 表示当前对象拥有多个附属对象,这些附属对象会被视为一个可枚举的集合,一旦 has_many 设置成功,当前对象会自动获得许多方法,可以追加对象可以遍历附属对象,在附属对象集合的修改和删除保存时都能反映在关联的表中。

以 Project 为例,has_many 会自动生成以下方法:

  • project.tasks: 返回 project 关联的 task 的集合,类似于 Task.find_by(project_id: #{id})
  • project.task << task: 为 project 追加一个 task
  • project.tasks.delete(task): 删除 task
  • project.tasks = tasks: 替换 project 附属的 tasks
  • project.task_ids: 返回 project 中所包含的 task 对象的 id
  • project.tasks.clear: 清空 project 下的 task
  • project.tasks.empty?: 判断 project 附属的 tasks 是否为空
  • project.tasks.size: 获取附属 tasks 集合的长度
  • project.tasks.build: 为 project 直接创建新的任务,类似于 Task.new(project_id: #{id})
  • project.tasks.create: 为 project 直接创建新的任务,类似于 t = Task.new(project_id: #{id}).save

创建相关 Task 和 Project 数据,这些数据会存储在数据库表中

图片.png

project.tasks 方法演示:

图片.png

project.task << t 方法演示:

图片.png

获取 project 附属 task 的 id 集合

图片.png

判断 project 附属 tasks 集合是否为空

图片.png

belong_to 的意思是当前对象从属于一个付对象, belongs_to 方法于 has_one 方法的使用非常类似,具有相同的参数设置,唯一不同的是从属方向不同

以 Task 为例,belongs_to 自动生成的方法有

  • taks.project: 返回于当前 task 关联的 project
  • task.project = p: 设置与当前 task 关联的 project
  • task.project.nil?: 返回 task 是否关联某个具体的project

多对多

开发人员(Developer)和任务(Task)是多对多的关系,一个任务可能有多个开发人员负责,一个开发人员也可能会负责多个任务,这就是多对多的关系

图片.png

多对多关系在数据库中通过中间表实现,中间表记录了对应关系

创建 Developer 模型,建立和 Task 对应关系

class Developer < ApplicationRecord
  has_and_belongs_to_many :tasks
end
class Task < ApplicationRecord
  belongs_to :project
  has_and_belongs_to_many :developers
end

Rails 中通过 has_and_belongs_to_many 来表示多对多关系,该方法本质上就等于 has_many 方法,在参数上同样具有 class_name, :conditions :dependent :include,自动生成的方法也与 has_many 方法一致, 等参数,具体可以参考 Project 和 Task 的 has_many 生成的方法。