【问题标题】:ActiveSupport::Concern should be included or extended应包含或扩展 ActiveSupport::Concern
【发布时间】:2020-09-21 22:32:17
【问题描述】:

我知道 include 用于将模块方法作为实例方法访问,而 extend 用于将模块方法作为类方法访问。

对于 ActiveSupport::Concern,我看到某处写成,

module Test
  include ActiveSupport::Concern
end

虽然在某些地方写成,

module Test
  extend ActiveSupport::Concern
end

我的困惑是,ActiveSupport::Concern 应该与 include 或 extend 一起使用?

【问题讨论】:

  • 您能否进一步指定“一些地方”?你的意思是网上随机的还是官方文档里的?
  • 似乎那篇文章的作者不明白ActiveSupport::Concern 的用途。 include ActiveSupport::Concern 在他的示例中实际上什么都不做,可以在不破坏代码的情况下删除。

标签: ruby-on-rails ruby


【解决方案1】:

您应该使用extend ActiveSupport::Concern,如documentation 中的示例所示。

通过使用ActiveSupport::Concern,上述模块可以改为 写成:

require 'active_support/concern'

module M
  extend ActiveSupport::Concern

  included do
    scope :disabled, -> { where(disabled: true) }
  end

  class_methods do
    ...
  end
end

使用extend 的原因是为了使ActiveSupport::Concern 中定义的方法在模块上下文中可用。这允许您在模块中使用方法includedclass_methods

使用include 时,这些方法在模块中不可用,而是在包含M 的类的实例上可用。

如果你想知道两者之间的区别,我建议看看What is the difference between include and extend in Ruby?

【讨论】:

  • 我知道包含与扩展差异,我的困惑在于 ActiveSupport::Concern。我也检查了这个 API 文档,但不清楚。你能详细说明为什么扩展而不包括 ActiveSupport::Concern
  • @RajKumarSharma 我已经用一个小解释更新了答案。
【解决方案2】:

您需要使用ActiveSupport::Concern 扩展模块,以使ActiveSupport::Concern#included#class_methods 方法正常工作。

这两种方法毕竟几乎是它存在的唯一原因。

module A
  extend ActiveSupport::Concern
  # raises ArgumentError (wrong number of arguments (given 0, expected 1))
  included do
    puts "Hello World"
  end
end

module B
  extend ActiveSupport::Concern
  included do
    puts "Hello World"
  end
end

class C
  include B
end
# Outputs Hello World

看看如果我们检查 included 方法会发生什么:

module AB
  include ActiveSupport::Concern
  puts method(:included).source_location # nil
end
module ABC
  extend ActiveSupport::Concern
  puts method(:included).source_location # .../ruby/gems/2.7.0/gems/activesupport-6.0.2.1/lib/active_support/concern.rb
end

当我们用ActiveSupport::Concern 扩展模块时,我们将它放在ABC 的祖先链上,因此ActiveSupport::Concern 的方法可以作为ABC 的模块方法使用。当您使用include 并且调用的included 方法实际上是Module#included from the Ruby core 时,不会发生这种情况。

【讨论】:

  • 很好的例子,谢谢,所以我们总是要扩展对吗?
  • 是的。由于 ActiveSupport::Concern 的重点是将其方法用作模块方法。它不为类提供任何使用的实例方法。
  • 如果你打算自己做一些元编程,可能会有一些边缘场景,你可能想include。然而,99.99% 的时间extend 是要走的路。
  • @3limin4t0r 如果你在做额外的元编程,我一开始就不会使用 ActiveSupport::Concern,因为它的功能实际上很容易在你喜欢的任何疯狂的恶作剧中被淘汰减少复杂性。但这只是我的 2c。
猜你喜欢
  • 2015-12-29
  • 2013-02-01
  • 2011-09-05
  • 1970-01-01
  • 2012-09-14
  • 1970-01-01
  • 2012-05-10
  • 2013-05-26
  • 2023-04-05
相关资源
最近更新 更多