如何解决Rails类如何直接在类上调用方法
我想进一步了解Rails的神秘方式,但我有以下问题。
例如,当我上课时我可以直接调用方法的模型,而无需将方法调用放在模型上的方法内部。
例如:
Post < ApplicationRecord
has_many :comments
end
在这种情况下,has_many
是一个方法调用,但它只是位于我的Post类中,而没有位于方法内部。如果我尝试在一个空白的ruby项目中做同样的事情,那是行不通的。
例如
class ParentClass
def say_hello
p "Hello from Parent Class"
end
end
class ChildClass < ParentClass
say_hello
end
child = ChildClass.new
# => undefined local variable or method `say_hello' for ChildClass:Class (NameError)
那么Rails是如何做到的?我一直都看到它,甚至看到一些添加这些方法调用的宝石,例如acts_as_votable
谁能解释发生了什么事?
解决方法
这里有两个重要的概念-第一个是在Ruby中,与像Java这样的经典语言不同,类主体只是一个可执行代码块:
class Foo
puts "I can do whatever I want here!!!"
end
class
只需声明常量(或在类已经存在的情况下重新打开它)并在要创建(或重新打开)的类的上下文中执行该块。此类是Class类的一个实例,我们称其为 singleton类或 eigenclass ,这可能是一个令人困惑的概念,但是如果您在Ruby中考虑到这一点,它会有所帮助一个对象和类仅仅是用于创建实例的蓝图的对象,因此可以具有自己的方法和属性。
第二个概念是内隐自我。在Ruby方法中,调用始终有一个收件人-如果您未指定收件人,则假定其为self
。类缩减模块中的self
是类本身:
class Bar
puts name # Bar
# is equivalent to
puts self.name
end
因此,您可以通过简单地将方法定义为类方法而不是实例方法来修正示例:
class ParentClass
def self.say_hello
p "Hello from Parent Class"
end
say_hello # Hello from Parent Class
end
has_many
仅仅是从ActiveRecord::Base
继承下来的类方法,它通过添加方法来修改类本身。
class Thing < ApplicationRecord
puts method(:has_many).source_location # .../activerecord-6.0.2.1/lib/active_record/associations.rb 1370
end
Ruby有许多此类元编程的示例,例如内置的#attr_accessor
方法,它们通常被称为宏方法。一旦掌握了元编程概念,这些方法就非常简单:
class Foo
def self.define_magic_method(name)
define_method(name) do
"We made this method with magic!"
end
end
def self.define_magic_class_method(name)
define_singleton_method(name) do
"We made this method with magic!"
end
end
define_magic_method(:bar)
define_magic_class_method(:bar)
end
irb(main):048:0> Foo.new.bar
=> "We made this method with magic!"
irb(main):048:0> Foo.baz
=> "We made this method with magic!"
这并不是真正的魔术-它只是修改类本身的类方法。
,这是因为has_many是在ApplicationRecord的类级别定义的。如果将ParentClass中的#say_hello方法更改为类方法,则该方法有效。这就是我的意思:
class ParentClass
def self.say_hello
p "Hello from the parent class"
end
end
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。