Arnold Roa
Arnold Roa

Reputation: 7718

How to require a module that already exists on a gem? kind of monkey patching

I'm using the telegram-bot gem. It has a module called Telegram. I want to extend it to add one method as a shortcut for my most common call.

The method I want to create is Telegram.send_message(text) with my default configuration.

For doing so I added a telegram.rb file on app/models/telegram.rb that extend the original module:

 module Telegram
    def self.send_message(text, options={})
        #...
    end
 end

If on console I run Telegram.send_message it says undefined method. If I do require 'telegram' the send_message method now works, (i guess its not autoloaded as there is module called Telegram already (the one on the gem). Now I want to require it on app initialization,

What I first tried is add the require on my application.rb but it says cannot load such file, because, I guess the load_path does not includes app/models yet.

Where I can add the require?

Another alternative would be give it another name, like TelegramBot. But I don't like the idea of have Telegram and TelegramBot.

Other alternative would be add it to the initializers instead of app/models. But I think that folder is more for settings.

So, what is the best approach to do this?

Upvotes: 0

Views: 55

Answers (1)

coreyward
coreyward

Reputation: 80041

When you run a Rails app in development the default is to automatically reload some files/classes on each request, but this behavior causes issues if you're trying to do things that persist between requests within the autoreloaded folders (i.e., anything under app).

In your case, since the Telegram constant is already defined, the Rails code responsible for mapping a class name back to a file isn't even triggered, so the file isn't automatically required.

Your suggestion to move this to an initializer is a great idea. This behavior indeed belongs in an initializer.

For what it's worth, you can avoid reopening the Telegram class to add your method by creating a mixin:

module SpecialShortcut
  def foo
    # ...
  end
end

# config/initializers/telegram_extensions.rb
Telegram.extend(SpecialShortcut)

Upvotes: 2

Related Questions