Ern*_*est 5 ruby ruby-on-rails ruby-on-rails-3
我是PHP开发人员,目前我正在学习Rails(3),当然还有Ruby.我不想相信魔法,所以我尽可能地了解Rails背后发生的事情.我发现有趣的是类似于has_one或belongs_to在ActiveRecord模型中的方法调用.
我试图重现这一点,并带来了天真的例子:
# has_one_test_1.rb
module Foo
class Base
def self.has_one
puts 'Will it work?'
end
end
end
class Model2 < Foo::Base
has_one
end
Run Code Online (Sandbox Code Playgroud)
只是运行这个文件将输出"它会工作吗?",正如我所料.
在搜索rails源代码时,我找到了负责的函数:def has_one(association_id,options = {}).
这怎么可能,因为它显然是一个实例(?)而不是一个类方法,它应该不起作用.
经过一番研究,我找到了一个可以回答的例子:
# has_one_test_2.rb
module Foo
module Bar
module Baz
def has_one stuff
puts "I CAN HAS #{stuff}?"
end
end
def self.included mod
mod.extend(Baz)
end
end
class Base
include Bar
end
end
class Model < Foo::Base
has_one 'CHEEZBURGER'
end
Run Code Online (Sandbox Code Playgroud)
现在运行has_one_test_2.rb文件将输出I CAN HAS CHEEZBURGER.如果我理解这一点 - 首先发生的事情是Base类试图包含Bar模块.在包含该self.included方法时,调用该方法,该方法使用Baz模块(及其实例has_one方法)扩展Bar模块.所以在本质has_one方法中包含(混合?)到Base类.但是,我仍然没有完全理解它.Object#extend从模块中添加方法但仍然,我不知道如何使用extend重现此行为.所以我的问题是:
这到底发生了什么.我的意思是,还是不知道has_one方法怎么变成类方法?究竟是哪一部分造成的?
这种方法调用(看起来像配置)的可能性非常酷.有没有替代或更简单的方法来实现这一目标?
你可以extend和include一个模块.
extend 从模块中添加方法作为类方法更简单的实现示例:
module Bar
def has_one stuff
puts "I CAN HAS #{stuff}?"
end
end
class Model
extend Bar
has_one 'CHEEZBURGER'
end
Run Code Online (Sandbox Code Playgroud)
include 将模块中的方法添加为实例方法
class Model
include Bar
end
Model.new.has_one 'CHEEZBURGER'
Run Code Online (Sandbox Code Playgroud)
Rails使用它来动态地向您的类添加方法.
例如,您可以使用define_method:
module Bar
def has_one stuff
define_method(stuff) do
puts "I CAN HAS #{stuff}?"
end
end
end
class Model
extend Bar
has_one 'CHEEZBURGER'
end
Model.new.CHEEZBURGER # => I CAN HAS CHEEZBURGER?
Run Code Online (Sandbox Code Playgroud)