重写 ActiveSupport::Concern 模块中由同一模块中的 class 方法定义的方法
Overriding methods in an ActiveSupport::Concern module which are defined by a class method in the same module
我有一个 ActiveSupport::Concern 模块,大致如下所示:
module MyModel
module Acceptance
extend ActiveSupport::Concern
included do
enum status: [:declined, :accepted]
end
def declined!
self.status = :declined
# some extra logic
self.save!
end
def accepted!
self.status = :accepted
# some extra logic
self.save!
end
end
end
这只会被包含到 ActiveRecord classes 中,因此使用 enum
。基本上,我用我自己的一些额外的自定义逻辑覆盖了 ActiveRecord::Enum.enum
创建的 declined!
和 accepted!
方法。
问题是,这不起作用,因为当我调用 @model.declined!
时,它只是调用 declined!
的原始实现,而忽略了我的自定义方法。
看起来我的自定义方法被包含在调用 class 之前 包含的块被 运行 - 这意味着我的自定义方法被覆盖通过 enum
定义的那些,而不是相反。
在这种特殊情况下有一些简单的解决方法(例如,我可以将调用 enum
移回包含 class 并确保它位于行 include MyModel::Acceptance
之上,但我'我想知道是否有一种方法可以解决这个问题,同时将其全部保存在同一个模块中。
有什么方法可以在 included
中调用定义实例方法的 class 方法,然后从同一 Concern
模块中覆盖该实例方法?
我想你正在寻找 define_method
。
module MyModel
module Acceptance
extend ActiveSupport::Concern
included do
enum status: [:declined, :accepted]
define_method :declined! do
self.status = :declined
# some extra logic
self.save!
end
define_method :accepted! do
self.status = :accepted
# some extra logic
self.save!
end
end
end
end
我有一个 ActiveSupport::Concern 模块,大致如下所示:
module MyModel
module Acceptance
extend ActiveSupport::Concern
included do
enum status: [:declined, :accepted]
end
def declined!
self.status = :declined
# some extra logic
self.save!
end
def accepted!
self.status = :accepted
# some extra logic
self.save!
end
end
end
这只会被包含到 ActiveRecord classes 中,因此使用 enum
。基本上,我用我自己的一些额外的自定义逻辑覆盖了 ActiveRecord::Enum.enum
创建的 declined!
和 accepted!
方法。
问题是,这不起作用,因为当我调用 @model.declined!
时,它只是调用 declined!
的原始实现,而忽略了我的自定义方法。
看起来我的自定义方法被包含在调用 class 之前 包含的块被 运行 - 这意味着我的自定义方法被覆盖通过 enum
定义的那些,而不是相反。
在这种特殊情况下有一些简单的解决方法(例如,我可以将调用 enum
移回包含 class 并确保它位于行 include MyModel::Acceptance
之上,但我'我想知道是否有一种方法可以解决这个问题,同时将其全部保存在同一个模块中。
有什么方法可以在 included
中调用定义实例方法的 class 方法,然后从同一 Concern
模块中覆盖该实例方法?
我想你正在寻找 define_method
。
module MyModel
module Acceptance
extend ActiveSupport::Concern
included do
enum status: [:declined, :accepted]
define_method :declined! do
self.status = :declined
# some extra logic
self.save!
end
define_method :accepted! do
self.status = :accepted
# some extra logic
self.save!
end
end
end
end