相信學 rails 的一定對 attr_accessor
, has_many
, scope
這些不陌生
但是到底是為什麼可以在 model 裡面直接下這些 method?
先看一下 rails 的 model,可以這樣定義
1
2
3
4
5
6
7
8
9
10
11
12
13
| # 5.x.x
class Klass < ApplicationRecord
attr_accessor :name
has_many :books
scope :male, ->{ where(gender:1) }
end
# 4.x.x
class Klass < ActiveRecord::Base
attr_accessor :name
has_many :books
scope :male, ->{ where(gender:1) }
end
|
可以知道 model 裡的是 class
並且是繼承 ApplicationRecord
因此判斷可能是屬於 ApplicationRecord
或者是更上層的某一個物件
在 ruby 中,所有類別的類別都是 class 類別
1
2
3
4
5
6
7
8
| Object.class
# => Class
Kernel.class
# => Module
Module.class
# => Class
Class.class
# => Class
|
Class 的寫法
一般看到的 class
1
2
3
4
5
| class Klass
def hi
puts 'hi'
end
end
|
相當於
1
2
3
4
5
6
| # 所有類別的名字都是一個常數(大寫開頭),如果不是大寫就不會有自己的名字
Klass = Class.new do
def hi
puts 'hi'
end
end
|
既然知道了 model 裡的 class 實際上是 Class.new
接下來看一下 doc Class new
If a block is given, it is passed the class object, and the block is evaluated in the context of this class using class_eval.
意思是指,中間那段 Block 都會用 class_eval
來執行,
1
2
3
4
5
6
7
8
9
10
11
12
| Klass = Class.new do
def meth1
"hello"
end
def meth2
"bye"
end
end
a = Klass.new #=> #<Klass:0x007f916006aa60>
a.meth1 #=> "hello"
a.meth2 #=> "bye"
|
由此推斷以下相等
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| class Klass
attr_accessor :name
has_many :books
scope :male, ->{ where(gender:1) }
end
Klass = Class.new do
attr_accessor :name
has_many :books
scope :male, ->{ where(gender:1) }
end
class Klass; end
Klass.class_eval do
attr_accessor :name
has_many :books
scope :male, ->{ where(gender:1) }
end
|
由此可知,attr_accessor
, has_many
, scope
都是由上層物件所定義好的 method
看一下原始碼其中一段,可看到 has_many
,是在一個 module 裡面,應該是透過 include
或是 extend
的方式,變成了 class 的 methods
1
2
3
4
5
6
7
8
9
10
11
| # rails/activerecord/lib/active_record/associations.rb
# ...
module ClassMethods
# ...
def has_many(name, scope = nil, **options, &extension)
reflection = Builder::HasMany.build(self, name, scope, options, &extension)
Reflection.add_reflection self, name, reflection
end
# ...
end
# ...
|
主要是研究一下看 rails 一些特別的功能是怎麼來的,要仔細的話就要去挖原始碼才能知道了
參考文件