ruby-on-rails - rails(ActiveRecord) 如何在模型上定义类方法以及如何在需要时删除其中一个
问题描述
我试图在我对 Rails 和 ruby 的更深入理解的旅程中弄清楚这一点。
我所知道的是,我们可以通过调用:在对象上检查方法是否在 ruby 类中定义。method_defined?
由于所有类也是类的对象,Class
我们可以对类方法做同样的事情。例如,如果类Foo
定义了bar
类方法,则会发生以下情况:
Foo.method_defined? :bar #-> true
但是当对继承自ActiveRecord::Base
(直接或间接)的模型应用相同时。这导致:
User.method_defined? :all #-> false
User.method_defined? :count #-> false
我可以看到这里all
定义的方法,我正在努力匹配这些点并理解正在发生的事情。以及这些方法在没有作为类方法实现时如何在模型上工作,也没有任何时髦的业务正在进行(看起来)。method_missing
在它上面,如果我能得到相同的解释,例如rails为模型对象添加的实例方法,比如name
方法in User.first.name
(假设用户表有名称列)。将是一个加号。
最后,如果我们需要,一些关于如何删除其中一种方法的信息。
额外:如果我还可以知道如何重置User
类以在删除后再次定义方法,例如如果我count
根据评论中的建议删除方法:User.instance_eval { undef :count }
我也希望能够重新定义它。或者重新设置User
课程。load 'app/models/user.rb'
不在这里做这项工作。
更新:我想出了如何在取消定义模型的特征类中的方法之后重置类,User
然后load 'app/models/user.rb'
我必须明确地这样做Object.send(:remove_const, :User)
,所以 ruby 完全删除了类而不是加载的东西。
仍在努力消化所有这些,尤其是 rails 实现的工作原理。
解决方案
这里没有魔法
module X
def test
end
end
class A
extend X
end
class B
include X
end
A.method_defined? :test #false
B.method_defined? :test #true
所以它没有被定义,因为它是一个类方法并且类方法是在单例类中定义的。
method_defined?
检查该方法是否仅在类或其祖先中定义。
B.ancestors #[B, X, Object, Kernel, BasicObject]
A.ancestors #[A, Object, Kernel, BasicObject]
很简单,因为它是一个类方法
更新:添加更多跟踪到如何定义
- 该方法
all
的定义如https://github.com/rails/rails/blob/b9ca94caea2ca6a6cc09abaffaad67b447134079/activerecord/lib/active_record/scoping/named.rb中所述, 此模块扩展ActiveSupport::Concern
,这意味着如果您包含此模块,ClassMethods
则将添加其中的方法作为包含器的类方法(有关此https://api.rubyonrails.org/classes/ActiveSupport/Concern.html的更多信息) - 在此处的活动记录入口点https://github.com/rails/rails/blob/b9ca94caea2ca6a6cc09abaffaad67b447134079/activerecord/lib/active_record.rb#L151命名的模块在内部自动加载
Scoping module
,导致模块称为ActiveRecord::Scoping::Named
上述模块 - 在基类中,该
Scoping
模块包含在https://github.com/rails/rails/blob/b9ca94caea2ca6a6cc09abaffaad67b447134079/activerecord/lib/active_record/base.rb#L298中,它定义all
为类方法
所以它类似于上面的简单代码,但使用了一些ActiveSupport
魔法,如自动加载、egarloading 和关注点。
推荐阅读
- jenkins - 无论如何访问电子邮件分机模板中的管道全局变量
- javascript - 使用 webpack 构建时出错
- javascript - 从对象数组中获取数据
- python - ImportError:在 Mac 上为 Darkflow 安装 Cython 时没有名为“Cython”的模块
- vue.js - 使用 momentjs 从数组格式化日期时间
- apache-spark - 在 Spark 2.3.0 中读取 Zstandard 压缩文件
- python - 在没有 sudo previlage 的远程机器上运行 python 脚本
- javascript - 需要来自 w3school 示例的响应式顶部菜单(汉堡包)的解释
- typescript - 如何在严格检查对象的嵌套属性的同时优雅地覆盖对象
- javascript - AngularJS SlimFramework