覆盖 ActiveSupport::Concern 模块中由同一模块中的类方法定义的方法
Posted
技术标签:
【中文标题】覆盖 ActiveSupport::Concern 模块中由同一模块中的类方法定义的方法【英文标题】:Overriding methods in an ActiveSupport::Concern module which are defined by a class method in the same module 【发布时间】:2015-03-28 16:31:05 【问题描述】:我有一个 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 类中,因此使用enum
。基本上,我用我自己的一些额外的自定义逻辑覆盖了由ActiveRecord::Enum.enum
创建的declined!
和accepted!
方法。
问题是,这不起作用,因为当我调用@model.declined!
时,它只是调用declined!
的原始实现并忽略我的自定义方法。
看起来我的自定义方法被包含在调用类中之前包含的块正在运行 - 这意味着我的自定义方法被enum
定义的那些覆盖,而不是其他一路走来。
在这种特殊情况下有一些简单的解决方法(例如,我可以将调用 enum
移回包含类,并确保它在 include MyModel::Acceptance
行上方,但我想知道是否有办法解决这个问题问题,同时将它们全部放在同一个模块中。
有什么方法可以在included
中调用定义实例方法的类方法,然后在同一个Concern
模块中覆盖该实例方法?
【问题讨论】:
【参考方案1】:我想你正在寻找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
【讨论】:
您能否详细说明为什么会这样?在 Rails 3.2 中,@GeorgeMillo 的方式效果很好。在 Rails 4.2 中它没有。他们是否在内部更改了有关方法添加方式的某些内容? 我刚刚重新阅读了这个问题,那里有一种解释。但任何额外的信息将不胜感激:)以上是关于覆盖 ActiveSupport::Concern 模块中由同一模块中的类方法定义的方法的主要内容,如果未能解决你的问题,请参考以下文章
ActiveSupport::Concern 中的 InstanceMethods 模块.. 弃用警告
无法使用 cache_classes = true 为关注 (ActiveSupport::Concern::MultipleIncludedBlocks) 定义多个“包含”块
使用 Ruby on Rails ActiveSupport::Concern 功能时如何“嵌套”包含模块?
ActiveSupport::Concern 和 gem 'name_of_person'(300?) 的内部运行机制分析