3

I have created a file lib/ext/date.rb which extends the Date class with a method.

class Date
  def self.next_(weekday_string)
    // code here
  end
end

In my application.rb file I autoload everything in this ext folder

config.autoload_paths << "#{Rails.root}/lib/ext"

But I keep getting the error undefined method next_ for Date:Class

Calling this method from within the console works fine

load 'lib/ext/date.rb'; Date.next_('wednesday')
=> Wed, 07 Oct 2015

And yes, the server has been restarted before trying to use this extended method.

Cjmarkham
  • 9,484
  • 5
  • 48
  • 81

1 Answers1

6

I guess, your understanding of Rails autoload mechanism is fuzzy.

autoload_paths is used when rails tries to resolve undefined constant. Say, you access a User for the first time. No such class is loaded, so rails will look in its autoload paths and try find User there.

Your case is different. Date is certain to be present (as it is a system class). And thus rails will have no reason to access files in autoload paths.

Solution:

load the files explicitly. For example, in an initializer

# 00_monkey_patching.rb
Dir["#{Rails.root}/lib/monkey_patching/*.rb"].each do |file|
  require file
end
Sergio Tulentsev
  • 226,338
  • 43
  • 373
  • 367
  • So I need to specifically load this class in? – Cjmarkham Oct 02 '15 at 11:48
  • 1
    Yes, you need to explicitly load it. Perhaps, in an initializer. – Sergio Tulentsev Oct 02 '15 at 11:49
  • @CarlMarkham, also, [check out this guide](http://stackoverflow.com/a/5654580/2235594) to extend core classes. I find the solution more elegant than using `monkey_patching` as a folder name. – davegson Oct 02 '15 at 12:06
  • @TheCha͢mp: using monkey_patching describes the purpose very well. That's what you do, patch stuff. If you need to patch, say, Mongoid driver, then `core_ext` would be a misleading name (because mongoid is not "core"). Also, the only different thing here is the folder name. So it's at the same level of elegance. :) – Sergio Tulentsev Oct 02 '15 at 12:11
  • @TheCha͢mp: RE "genius" solution: it requires 3 lines less code, that's all. But drawbacks may be significant. Now your patches are scattered through the initializers folder. What if some of your other non-patching initializers rely on some patch, but that patch is not yet loaded at this point, due to lexicographical sorting? – Sergio Tulentsev Oct 02 '15 at 12:14
  • Ye you got your points... :) Anyway, it was helpful since I learnt something new from you. – davegson Oct 02 '15 at 12:59
  • I agree an initializer is probably the most appropriate place for something like this. – engineersmnky Oct 02 '15 at 14:06