首页 > 解决方案 > 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 实现的工作原理。

标签: ruby-on-railsrubyrails-activerecorddynamic-programming

解决方案


这里没有魔法

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]

很简单,因为它是一个类方法
更新:添加更多跟踪到如何定义

所以它类似于上面的简单代码,但使用了一些ActiveSupport魔法,如自动加载、egarloading 和关注点。


推荐阅读