表间关联 - 一对多和多对多
一对多
一对多关系有很多种,比如一篇文章会包含多个评论,而一个评论只能属于一个文章,文章和评论之间通过评论表中的文章 id 来实现关联,如下图所示:
通常项目(Project)和 任务(Task)是一对多关联的,一个项目中包含多个任务,而每个任务只能属于一个项目
使用命令行创建两个模型 Project 和 Task
rails g model project
rails g model task
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 表中创建了外键引用
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 数据,这些数据会存储在数据库表中
project.tasks 方法演示:
project.task << t 方法演示:
获取 project 附属 task 的 id 集合
判断 project 附属 tasks 集合是否为空
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)是多对多的关系,一个任务可能有多个开发人员负责,一个开发人员也可能会负责多个任务,这就是多对多的关系
多对多关系在数据库中通过中间表实现,中间表记录了对应关系
创建 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 生成的方法。