【问题标题】:ruby alias_method in class method类方法中的 ruby​​ alias_method
【发布时间】:2016-03-11 02:39:08
【问题描述】:

似乎 alias_method 在 class

这是我的用例:我正在覆盖从 ActiveRecord 基继承的 destroy 和 destroy_all 方法,因为当前编写的代码很容易在您打算删除连接记录时意外删除行。这种设计可能会随着一个更大的项目而改变,但现在这是我的解决方案,因为大多数情况下,没有人会想要从这个表中删除行。但是为了仍然允许出于善意的目的故意删除表中的行,我使用 alias_method 来保留原始destroy和destroy_all方法的句柄。使用别名可以访问原始 :destroy (instance) 方法,但不允许我访问原始 :desotry_all (class) 方法

class HoldReason < ActiveRecord::Base
  class << self
    alias_method :remove_hold_reasons_from_table, :destroy_all

    def destroy_all
      raise "Nope"
    end
  end

  alias_method :remove_hold_reason, :destroy

  def destroy
    raise "Nope"
  end
end

在这里我们看到,虽然这种策略确实适用于允许成功删除单行的实例方法:

> HoldReason.find_by(title: "Management Review").remove_hold_reason
  HoldReason Load (0.7ms)  SELECT  `hold_reasons`.* FROM `hold_reasons` WHERE `hold_reasons`.`title` = 'Management Review' LIMIT 1
   (0.5ms)  BEGIN
  SQL (4.6ms)  DELETE FROM `hold_reasons` WHERE `hold_reasons`.`id` = 23
   (0.6ms)  COMMIT
=> #<HoldReason id: 23, title: "Management Review", category: "Operations">

我无法访问原始的 :destroy_all 方法以在一个查询中删除多行;相反,即使我使用别名,我也会得到覆盖的方法:

> HoldReason.remove_hold_reasons_from_table
  HoldReason Load (0.7ms)  SELECT `hold_reasons`.* FROM `hold_reasons`
RuntimeError: Nope

发生了什么事,我似乎无法为类方法执行此操作,我该如何修复它(除了使用原始 SQL 查询进行删除)?

【问题讨论】:

  • 您的问题不清楚。您发布的代码 sn-p 清楚地表明 alias_method 确实 工作:否则您会得到 NoMethodError
  • 我已经编辑了这个问题。目的是使用别名可以让我在被覆盖以引发错误之前访问原始方法。这适用于实例方法,但不适用于类方法;在类方法的情况下,别名仍然使用被覆盖的方法,而在实例方法的情况下,当我使用别名时,我可以访问原始的非覆盖方法。
  • 对不起,我还是不明白。在这两种情况下,您都可以使用其别名调用该方法。所以,alias_method 在这两种情况下都有效。这两种情况没有区别。在Module 类中确实有一个 实现alias_method,它对所有 模块的工作方式完全相同,无论它们是实际模块、类或单例类。 alias_method 只做一件事:将方法复制到一个新名称下。时期。这是有效的,你没有得到NoMethodError这一事实就证明了这一点。
  • 另外,作为一般规则:如果你认为每天被成千上万的 Ruby 程序员广泛使用的方法被破坏,并且除了你之外没有人注意到......你非常可能是错的。
  • 好的,我希望能从这里的疑问中获得更多好处。我不是说这个关键方法坏了,那确实是我的愚蠢。我是说在这种特定情况下因为设置其他特定代码的方式,当人们打算从一个加入表。 > model.hold_reasons.destroy_all.

标签: ruby activerecord class-method alias-method


【解决方案1】:

答案是我没有得到新的 :destroy_all 方法;我正确地获得了旧的 :destroy_all 方法,这在引擎盖下称为 :destroy。当然,通过调用 :destroy,它得到了新的 :destroy 方法,该方法引发了错误。所以看起来我得到了新的类方法,因为新的类方法和新的实例方法引发了完全相同的错误。

如果我稍微修改一下就会更清楚:

class HoldReason < ActiveRecord::Base
  class << self
    alias_method :remove_hold_reasons_from_table, :destroy_all

    def destroy_all
      raise "Don't destroy_all (multiple: class method)"
    end
  end

  alias_method :remove_hold_reason, :destroy

  def destroy
    raise "Don't destroy (single: instance method)"
  end

end

结果

> HoldReason.remove_hold_reasons_from_table
RuntimeError: Don't destroy (single: instance method)

【讨论】:

    猜你喜欢
    • 2019-11-05
    • 2020-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-12
    • 2021-09-05
    相关资源
    最近更新 更多