今天我们进入 ActiveRecord 的部分,这可能是 Rails 中最常用的部分之一(或者没有之一)。
ActiveRecord 中常用的方法有:建立关联关系用的belongs_to
,has_many
等方法;建立数据验证用的validates
等方法;当然还有作为一个 ORM ,最基本的 CRUD 功能;当然还有连接数据库等的establish_connection
等方法。
我们先从 has_many
这个方法说起。
has_many
的第一个特点是,生成了很多实例方法,比如:
1 | class Product < ActiveRecord::Base |
会生成users
,users.create
等方法。这是怎么实现的呢?让我们来看看源代码。
has_many
方法是这么定义的:
1 | def has_many(name, scope = nil, options = {}, &extension) |
众所周知,这个方法可以接受很多可选的参数,如果没有那些参数,Rails 会给出默认值。我们这一阶段的主要目标是看看 Rails 如何利用has_many
生成那么多的实例方法,所以我们不会对 has_many
方法传很多options
。因此,在has_many
方法的内部,传入Builder::HasMany.build
方法的参数其实只有self
,也就是 has_many
方法被使用的那个 model,以及name
。
而在Builder::HasMany.build
方法中,我们可以很快的看到这些方法是如何被定义出来的:
1 | def self.build(model, name, scope, options, &block) |
这里插一句题外话,ruby 中的 class 也是对象,类方法其实是一个类的对象方法(或者叫单例方法,英文 singleton_method),这个 singleton_method 存放在这个对象的 singleton_class 中,singleton_class 会随着类的继承而出现在继承链中。所以尽管self.build
这个类方法是定义在ActiveRecord::Associations::Builder::Association
中的,继承了这个类的Builder::HasMany
也可以因此调用build
方法。
回到正题,我们看到上文self.build
方法中,extension 是define_extensions
的返回值,这个值只有在&block
存在的情况下,才会有非 nil 的返回值,否则返回值只能是 nil。具体原因可以看源代码。
更重要的是 reflection 这个值是create_reflection
方法的返回值,而在这个方法中:
1 | def self.create_reflection(model, name, scope, options, extension = nil) |
Rails 通过最后一行代码ActiveRecord::Reflection.create(macro, name, scope, options, model)
创建了很多东西。相比于这行代码,这个方法中的其他代码其实没那么重要,他们都是在判断参数是否合法,或者调整一些参数。
在ActiveRecord::Reflection.create
中到底创建了什么呢?
首先说,传进这个方法的 macro
是一个 symbol —— :has_many
,有兴趣的可以自己看看源代码。name
也是一个 symbol,在我们的文章中,这个参数是 :users
,而model
就是Product
中的model。
这里再插入一个题外话,macro
在中文世界里通常被翻译为宏,或者宏指令,我以前在使用微软的 office 办公软件时,经常会被提醒是否禁用宏。这里的宏的英文应该也就是 macro
了。宏这个翻译或许有他抽象的意义,但真的不够直观,如果这个词忽然出现在一个人的 office 软件的提示框里,会让很多人有不明所以的感觉。那么宏到底是什么呢,我们能不能给他一个更直观的翻译呢?节省一下非 developer 的使用者的认知成本呢?
我们下次继续