Today I was debugging some RSpec tests that were failing intermittently. Eventually I narrowed the issue down to Devise’s active_for_authentication? method, which was sometimes returning true and sometimes false.

I tried looking up the source code and had a WTF moment when I saw how active_for_authentication? is defined in the Devise::Models::Authenticable module:

def active_for_authentication?
  true
end

Source

After a bit of research I learned via StackOverflow that you can use the method method to find out where an object gets a method from. This showed me that my user model was actually using the active_for_authentication? method defined in Devise::Models::Confirmable, not Devise::Models::Authenticable.

user.method(:active_for_authentication?)
#=> #<Method: User(Devise::Models::Confirmable)#active_for_authentication?>

This version of the function was a bit more complicated than merely returning true. Sanity restored.

def active_for_authentication?
  super && (!confirmation_required? || confirmed? || confirmation_period_valid?)
end

Source

Eventually, I realized that the failing tests were caused by calling Timecop.freeze in an unrelated test without calling Timecop.return, which was messing with one of the time-based checks Devise does.

More about the method method:

It returns an object of class Method, which has a lot of other useful methods you can call:

user.method(:active_for_authentication?).source_location
#=> ["/path/to/file.rb", 144]

user.method(:active_for_authentication?).owner                 
#=> Devise::Models::Confirmable

user.method(:active_for_authentication?).parameters         
#=> []

You can also perform sorcery like assigning methods to variables and calling them, which I’m sure is useful sometimes although I can’t imagine such a scenario:

m = 12.method("+")
m.call(3)    #=> 15
m.call(20)   #=> 32

Source

The first thing they tell you when you start learning Ruby is “everything is an object”. I feel like I understand this better every day, even after two years of writing Ruby. Yes, everything is an object, including methods.