Reputation: 248
I have a web app built on Ruby on Rails. In this app obviously use different Gems. Iv come to a point where i want to extend some specific gem's classes, and add methods to it.
Now i have a use case where i want to extend a gem's class, but instead of adding methods, i want to change its inherting class lets take the Impressionist Gem for example:
Iv created a new class in my app - app/models/impression.rb
class Impression < ActiveRecord::Base
establish_connection(ENV[App_LOGS_DB'])
end
i want to change the Inheritance to use a my custom class called LogsBase
class Impression < LogsBase
end
the LogsBase class is definend as follows:
class LogsBase < ActiveRecord::Base
establish_connection ENV['APP_LOGS_DB']
self.abstract_class = true
end
When in try to run the server, the following exception is raised:
/gems/impressionist-1.6.1/lib/impressionist/models/active_record/impression.rb:5:in `<main>': superclass mismatch for class Impression (TypeError)
which from my understanding basically means there is a conflict between the gem's impression class definition and my own extention of that class.
Can anyone please help in finding out a way that i can change the Impression class inherting class, while still perserving the class's behaviour and making my server run properly?
PS: the goal of all this is to write the impressions data into a different database (logs db) rather than the main app db. in order to do that i need to establish a connection to the logs db, but if ill do it within the Impression class directly , it will blow up my pool of DB connections as indicated in the following link:
https://www.thegreatcodeadventure.com/managing-multiple-databases-in-a-single-rails-application/
thats why i need the abstract LogsBase class.
Any help will be appreciated.
Upvotes: 0
Views: 1339
Reputation: 28305
There is no (sensible) way to redefine a base class in ruby. It's possible, but only via weird hacks.
I would suggest taking one of two routes here:
establish_connection ENV['SPLACER_LOGS_DB']
into a module, and include
it in the class.I would be inclined to use option 2 for now, as it's a quick/simple workaround that should fit well with the rest of the application.
Upvotes: 1
Reputation: 121010
Disclaimer: do not do that!
The only way I can think of is a nasty hack, neither reliable, nor robust, that is not compatible with newer versions of your external gem. Since Ruby does not allow to redefine the classes ancestors, you might (but please don’t):
/gems/impressionist-1.6.1/lib/impressionist/models/active_record/impression.rb
file./blah/foo/impression
.impressionist/models/active_record/impression
explicitly.Something like this:
require 'impressionist/models/active_record/impression'
Object.send :remove_const, 'Impression'
class Impression < LogsBase
# ORIGINAL CONTENT OF THIS FILE
end
Upvotes: 1