ruby on rails中Model的关联详解
Rails中Model关联需在两端声明,遵循命名惯例:belongs_to后跟单数,has_many后跟复数。一对多通过外键实现,如妈妈与儿子;多对多借助中间表,如学生与老师通过课程表关联。掌握这些基础可高效处理复杂关联。
在开始学习 Rails 的 Model 关联之前,有几个关键点值得先刻在脑子里:关联关系必须在两端都声明清楚,否则很容易出现让初学者摸不着头脑的错误——而且这对理解代码逻辑也大有裨益。Model 名称用单数,Controller 名称用复数;belongs_to 后面必须是单数且小写,has_many 后面则是复数。这些约定俗成的规则,背后是 Rails 的“惯例优先配置”哲学,理解了它们,后续的代码阅读和编写都会顺畅很多。

一、一对多
举个生活中的例子:王妈妈有两个孩子,小明和小亮。可以说“王妈妈有多个孩子”,也可以说“小明有一个妈妈”“小亮有一个妈妈”。在数据库设计时,我们通常会这样规划:
mothers表:id、namesons表:id、name
为了建立逻辑关系,需要在“多”的一方(即 sons 表)增加一列作为外键,所以 sons 表实际上有三列:id、name、mother_id(对应 mothers 表的 id)。
如果用原生 SQL 查询,比如找出“小李”的妈妈的名字,你会写:
select test_associate.mothers.name from test_associate.mothers inner join test_associate.sons on sons.mother_id = mothers.id where sons.name = '小李'
换成 Ruby 代码就简洁多了:
class Mother has_many :sons end class Son belongs_to :mother end
逻辑很清楚:一个妈妈有多个孩子,一个儿子属于一个妈妈。在 Rails console 里测试一下:
xiao_wang = Son.first mom = xiao_wang.mother
这里的 .mother 方法就是由 class Son 中的 belongs_to :mother 自动生成的。它背后产生的 SQL 相当于:
select * from mothers join sons on sons.mother_id = mothers.id where sons.id = 1
这里有一个细节值得展开:
belongs_to :mother是简写,完整写法是belongs_to :mother, :class => 'Mother', :foreign_key => 'mother_id'。两者完全等价。- Rails 正是通过这种“惯例”来推断:
belongs_to :mother告诉它,mothers表是“一”的那一端,而当前类Son对应sons表,外键是mother_id(默认命名规则)。 - 因为外键保存在“多”的一端(
sons表),所以sons表中必须有一个mother_id列。
配置好之后,调用方式非常自然:
son = Son.first son.mother # .mother 方法由 belongs_to 产生 mother = Mother.first mother.sons # .sons 方法由 has_many 产生
二、一对一
一对一关系相对简单,实际使用频率也不高(比如老公和老婆),这里就不展开介绍了。
三、多对多
再来看一个学生和老师的例子:一个学生有多位老师(学习了多门课程),一个老师也可以教多个学生(一门课程有多个学生来听)。这种情况下,直接把外键放在学生表或老师表里都不合适,需要一张中间表(桥梁表)来记录关联。
表结构设计如下:
students表:id、nameteachers表:id、namelessons表(中间表):id、name、student_id、teacher_id
对应的原生 SQL 查询,比如找出“小王”的所有老师,可能会写成:
select teachers.*, students.*, lessons.* from lessons, teachers join teachers on lessons.teacher_id = teachers.id join students on lessons.student_id = students.id where students.name = '小王'
而在 Rails 中,只需要在 Model 里声明 has_many :through 即可:
class Student has_many :lessons has_many :teachers, :through => :lessons end
注意,has_many :teachers, :through => :lessons 其实等价于 has_many :teachers, :class => 'Teacher', :foreign_key => 'teacher_id', :through => :lessons,但 Rails 的惯例足以推断出这些细节。
同样的,Teacher 类也需要声明关联:
class Teacher has_many :lessons has_many :students, :through => :lessons end
这样一来,查询“小王的老师有哪些”就变得极其直观:
Student.find_by_name('小王').teachers
以上就是 Rails 中 Model 关联的几种核心模式。理解这些基础之后,你会发现实际项目中的复杂关联无非是这些基本模式的组合与变种。掌握好它们,后续的代码阅读和数据库设计都会事半功倍。


































