Search code examples
rubyrake

How do I override a method in ruby for a one time rake task?


I want to run a service object in a rake task but need to change a method in a different service that my main service object calls. For example if I have:

main_service.rb

class MainService
  def perform
    SecondaryService.new.perform
  end
end

secondary_service.rb

class SecondaryService
  def perform
    some_method
  end

  def some_method
    puts 'something'
  end
end

And I want to change some_method to be puts 'anything' for a one time data fix in a rake task, could I override it by simply redefining the method and is there a way to scope it to just the rake task? I don't want this service to accidentally be called while I run the rake task in case. I was thinking something like this:

one_time.rake

class SecondaryService
  def some_method
    puts 'anything'
  end
end

def one_time_change
  MainService.new.perform
end

Solution

  • The code you've suggested should work fine. You could go with that.

    However, depending on the context, there is a risk that this strategy may have unintended consequences - i.e. What happens if you accidentally execute the class monkey-patching but expected the original behaviour to be preserved?

    A more robust approach is to use dependency injection. By doing this, you can override behaviour with classical inheritance (or even by passing an entirely new object!). For example, something like:

    class MainService
      def perform(secondary_service: SecondaryService.new)
        secondary_service.perform
      end
    end
    
    class ModifiedSecondaryService < SecondaryService
      def some_method
        puts 'anything'
      end
    end
    

    Now, for your one-off rake task, you can run:

    PrimaryService.new.perform(secondary_service: ModifiedSecondaryService.new)