我从来不明白为什么必须使用ActiveSupport :: Concern而不是普通模块来使用mixins。对于ActiveSupport :: Concern提供的功能(至少在Rails 5中),是否有一个简单的答案,即不使用ActiveSupport :: Concern的简单模块可以做什么?
答案 0 :(得分:3)
来自https://api.rubyonrails.org/classes/ActiveSupport/Concern.html:
一个典型的模块如下:
module M
def self.included(base)
base.extend ClassMethods
base.class_eval do
scope :disabled, -> { where(disabled: true) }
end
end
module ClassMethods
...
end
end
通过使用ActiveSupport::Concern
,上述模块可以改为:
require 'active_support/concern'
module M
extend ActiveSupport::Concern
included do
scope :disabled, -> { where(disabled: true) }
end
class_methods do
...
end
end
此外,它可以优雅地处理模块依赖性。给定一个Foo
模块和一个Bar
模块(取决于前者),我们通常将编写以下内容:
module Foo
def self.included(base)
base.class_eval do
def self.method_injected_by_foo
...
end
end
end
end
module Bar
def self.included(base)
base.method_injected_by_foo
end
end
class Host
include Foo # We need to include this dependency for Bar
include Bar # Bar is the module that Host really needs
end
但是,Host
为什么要关心Bar
的依存关系,即Foo
?我们可以尝试在Host
中直接将Foo
中的Bar
隐藏在module Bar
include Foo
def self.included(base)
base.method_injected_by_foo
end
end
class Host
include Bar
end
中:
Foo
不幸的是,这不起作用,因为当包含Bar
时,它的基础是Host
模块,而不是ActiveSupport::Concern
类。使用require 'active_support/concern'
module Foo
extend ActiveSupport::Concern
included do
def self.method_injected_by_foo
...
end
end
end
module Bar
extend ActiveSupport::Concern
include Foo
included do
self.method_injected_by_foo
end
end
class Host
include Bar # It works, now Bar takes care of its dependencies
end
,可以正确解决模块依赖性:
{{1}}