我从来不明白为什么必须使用ActiveSupport :: Concern来用于mixins而不是普通模块。对于ActiveSupport :: Concern提供的功能(至少在Rails 5中),是否有一个简单的答案,即不使用ActiveSupport :: Concern的简单模块可以做什么?
来自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
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句