Andy
Andy

Reputation: 11008

How to extend class Object in Rails?

I would like to add method nil_or_empty? to all classes, therefore I define

module ObjectExtensions
  def nil_or_empty?
    return self.nil? || (self.respond_to?('empty?') && self.empty?)
  end
end
::Object.class_eval { include ::ObjectExtensions }

It works fine in a simple Ruby script

p nil.nil_or_empty? #=> true
p ''.nil_or_empty? #=> true
p [].nil_or_empty? #=> true
p 0.nil_or_empty? #=> false

However, when I add it to my library file lib/extensions.rb in a Rails 3 app, it seems to be not added

NoMethodError (undefined method `nil_or_empty?' for nil:NilClass):
  app/controllers/application_controller.rb:111:in `before_filter_test'

I do load the library file (all other extensions from that file are working fine) and

# config/application.rb
# ...
config.autoload_paths << './lib'

Where am I wrong?

Upvotes: 8

Views: 6790

Answers (2)

PreciousBodilyFluids
PreciousBodilyFluids

Reputation: 12011

First, it's cleaner to just reopen the Object class directly:

class Object
  def nil_or_empty?
    nil? || respond_to?(:empty?) && empty?
    # or even shorter: nil? || try(:empty?)
  end
end

Second, telling Rails to autoload /lib doesn't mean that the files in /lib will be loaded when your app starts up - it means that when you use a constant that's not currently defined, Rails will look for a file in /lib corresponding to that constant. For example, if you referred to ObjectExtensions in your Rails app code, and it wasn't already defined somewhere, Rails would expect to find it in lib/object_extensions.rb.

Since you can't extend a core class in /lib like this, it's a better idea to put core extensions in your config/initializers directory. Rails will load all the files in there automatically when your app boots up. So try putting the above Object extension in config/initializers/object_extension.rb, or config/initializers/extensions/object.rb, or something similar, and everything should work fine.

Upvotes: 18

Henrik N
Henrik N

Reputation: 16294

In this particular case, you could just use the Rails-provided Object#blank?. For the inverse, there is Object#present?.

#blank? is like your method but also considers all-whitespace strings like "   " to be blank.

Upvotes: 8

Related Questions