仅列出 ActiveRecord 子类方法

Posted

技术标签:

【中文标题】仅列出 ActiveRecord 子类方法【英文标题】:List only ActiveRecord subclass methods 【发布时间】:2012-02-26 21:43:15 【问题描述】:

给定以下 ActiveRecord 模型:

class User < ActiveRecord::Base
  has_many :games
  def name
    "Joe"
  end

  def city
     "Chicago"
  end
end

我想检索我直接添加到 User 类的方法列表(而不是通过扩展 ActiveRecord 和/或添加关联添加的方法)。示例输出:

["name","city"]

调用 User.instance_methods(false) 返回 ActiveRecord 添加的方法:

["validate_associated_records_for_games", "games", "game_ids", "games=", "game_ids=", "after_create_or_update_associated_records_for_games", "before_save_associated_records_for_games"]

连同来自数据库列的任何模型属性。我想排除这些,只获取子类上的自定义方法。

我的目的是方法跟踪:我想跟踪我的自定义方法,同时排除 ActiveRecord 添加的方法。

有什么想法吗?

【问题讨论】:

你用的是什么版本的rails? 我正在使用 Rails 2.2.2 进行测试,但我愿意接受更新版本的解决方案。 在 Rails 3.2 中,属性访问器、关联访问器以及可能的验证内容都在您的模型中包含的方法中定义,这使您尝试做的事情更容易 【参考方案1】:
User.instance_methods - ActiveRecord::Base.instance_methods #=> [:name,:city]

更新:

这些方法的顺序很重要

class User < ActiveRecord::Base
  def self.my_own_methods
    self.instance_methods - @@im
  end
  has_many :games
  @@im = self.instance_methods
  def name
    "Joe"
  end
  def city
    "Chicago"
  end
end

User.my_own_methods #=> [:name, :city]

这个已经测试过了

【讨论】:

这不起作用,因为AR自动生成的方法(例如DB列的方法)不会在ActiveRecord::Base.instance_methods中。 是的 - 这将返回 ActiveRecord 添加到 User 类的方法。例如,您会看到像 :games= 这样的输出,这是我不想要的,但由于 has many :games 关联而被包含在内。 是的 - 这很有效,而且很简单。缺点是在所有 ActiveRecord 模型中实现它不会是 DRY 并且需要记录方法排序。【参考方案2】:

使用 method_added 钩子将方法名称添加到列表中,并使用猴子补丁 Active Record 以便 AR 添加的方法不会添加到该列表中。

如果您不想打开 AR 并开始四处寻找,您还可以定义一个“类宏”,它定义一个方法将其添加到列表中。对于您自己的自定义方法,请使用类宏而不是 def

如果你不熟悉我所说的“类宏”,它只是一个这样的方法:

class Class
  def mydef(name,&block)
    (@methods || []) << name
    define_method(name,&block)
  end
end

使用mydef 之类的东西而不是def 来定义方法绝对是丑陋的,但它无需任何猴子补丁就可以解决问题。

【讨论】:

澄清一下,“类宏”是Class 上的一个实例方法,您可以从class 块中调用它来定义方法等。attr_accessor 是另一个示例。跨度> 方法的参数呢? 如果传递给define_method的块接受参数,生成的方法也会接受参数。 是的 - 这会起作用。就像你说的,我需要跨模型更改我的方法定义。不过我喜欢这个方向:我已经重写了 ActiveRecord::Base 的 extend 方法来添加对子类的 method_added 调用。它检查第一个调用者的文件名是否与子类匹配。如果是这样,它将方法名称添加到数组中。这并不完美,但它确实抓住了模型文件中定义的所有方法。 好主意,我喜欢!如果此答案可以帮助您解决问题,我们将不胜感激。如果您可以分享可能对未来读者有用的代码,您可以编辑这篇文章以添加它(我会批准编辑)。

以上是关于仅列出 ActiveRecord 子类方法的主要内容,如果未能解决你的问题,请参考以下文章

覆盖ActiveRecord子类中的'=='方法有意义吗?

ActiveRecord 子类化?

ActiveRecord:从控制台列出表中的列

为啥 Rails 5 使用 ApplicationRecord 而不是 ActiveRecord::Base?

ActiveRecord Rails 3 范围与类方法

修改 ActiveRecord 属性仅用于保存