I have an ActiveSupport::Concern module which looks roughly like the following:
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
This is only ever going to be included into ActiveRecord classes, hence the use of enum
. Basically, I'm overriding the declined!
and accepted!
methods that are created by ActiveRecord::Enum.enum
with some extra, custom logic of my own.
The problem is, this doesn't work, because when I call @model.declined!
it justs call the original implementation of declined!
and ignores my custom method.
Looks like my custom methods are being included into the calling class before the included block is being run - meaning my custom methods are being overridden by the ones defined by enum
, instead of the other way around.
There some easy workarounds in this particular situation (e.g. I could move the call enum
back into the including class and make sure it's above the line include MyModel::Acceptance
, but I'm wondering if there's a way I can solve this problem while keeping it all in the same module.
Is there any way I can call a class method within included
that defines an instance method, then override that instance method from within the same Concern
module?
I think you're looking for 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
来源:https://stackoverflow.com/questions/28214874/overriding-methods-in-an-activesupportconcern-module-which-are-defined-by-a-cl