Search code examples
ruby-on-railsrubymonkeypatching

Monkey patch method on single object


I would like to override the behavior of the update_attributes method on a single instance of a model class. Assuming the variable is called @alert what is the best way to go about this? To be clear, I do not want to modify the behavior of this method for the entire class.


DISCLAIMER:

I need to do this to force the method to return false when I want it to so that I can write unit tests for the error handling code following. I understand it may not be the best practice.


Solution

  • Just define a method on the object:

    class Thing
      def greeting
        'yo, man'
      end
    end
    
    Thing.instance_methods(false)
      #=> [:greeting]
    
    object = Thing.new
      #=> #<Thing:0x007fc4ba276c90> 
    
    object.greeting
      #=> "yo, man" 
    

    Define two methods on object (which will be instance methods in object's singleton class.

    def object.greeting
      'hey, dude'
    end
    
    def object.farewell
      'see ya'
    end
    
    object.methods(false)
      #=> [:greeting, :farewell] 
    object.singleton_class.instance_methods(false) #=> [:greeting, :farewell]
    
    object.greeting
      #=> "hey, dude" 
    object.farewell
      #=> "see ya"
    
    new_obj = Thing.new
    new_obj.greeting
      #=> "yo, man"
    new_obj.farewell
      #NoMethodError: undefined method `farewell' for #<Thing:0x007fe5a406f590>
    

    Remove object's singleton method greeting.

    object.singleton_class.send(:remove_method, :greeting)
    
    object.methods(false)
      #=> [:farewell] 
    object.greeting
      #=> "yo, man"
    

    Another way to remove :greeting from the object's singleton class is as follows.

    class << object
      remove_method(:greeting)
    end