Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overriding methods in an ActiveSupport::Concern module which are defined by a class method in the same module

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?

like image 798
GMA Avatar asked Jan 29 '15 12:01

GMA


1 Answers

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
like image 98
Chip Avatar answered Oct 12 '22 21:10

Chip