Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 739
Steve Avatar asked Jun 04 '15 20:06

Steve


2 Answers

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
like image 176
Cary Swoveland Avatar answered Nov 15 '22 15:11

Cary Swoveland


After creating an object, call "define_method" on it:

object = Thing.new
object.define_method("update_attributes") { return false }

That done, object.update_attributes should now return false

like image 24
David Hoelzer Avatar answered Nov 15 '22 17:11

David Hoelzer