Ruby on Rails расширяет класс гема и изменяет его наследующий класс
У меня есть веб-приложение, построенное на Ruby on Rails. В этом приложении очевидно использовать разные драгоценные камни. Я дошел до того, что я хочу расширить некоторые классы гемов и добавить к ним методы.
Теперь у меня есть сценарий использования, в котором я хочу расширить класс гема, но вместо добавления методов я хочу изменить его наследующий класс, например, возьмем импрессионистский гем:
Iv создал новый класс в моем приложении - app/models/impression.rb
class Impression < ActiveRecord::Base
establish_connection(ENV[App_LOGS_DB'])
end
я хочу изменить Наследование, чтобы использовать мой собственный класс с именем LogsBase
class Impression < LogsBase
end
класс LogsBase определяется следующим образом:
class LogsBase < ActiveRecord::Base
establish_connection ENV['APP_LOGS_DB']
self.abstract_class = true
end
При попытке запустить сервер возникает следующее исключение:
/gems/impressionist-1.6.1/lib/impressionist/models/active_record/impression.rb:5:in `<main>': superclass mismatch for class Impression (TypeError)
что из моего понимания в основном означает, что существует конфликт между определением класса впечатлений драгоценного камня и моим собственным расширением этого класса.
Может кто-нибудь помочь, пожалуйста, выяснить, как я могу изменить класс наследования класса Impression, сохраняя при этом поведение класса и обеспечивая правильную работу моего сервера?
PS: цель всего этого - записать данные о впечатлениях в другую базу данных (logs db), а не в основное приложение db. чтобы сделать это, мне нужно установить соединение с журналами базы данных, но если я сделаю это напрямую в классе Impression, он взорвет мой пул соединений с БД, как указано в следующей ссылке:
https://www.thegreatcodeadventure.com/managing-multiple-databases-in-a-single-rails-application/
Вот почему мне нужен абстрактный класс LogsBase.
Любая помощь будет оценена.
2 ответа
Отказ от ответственности: не делайте этого!
Единственный способ, которым я могу придумать, - это неприятный хак, ни надежный, ни надежный, который не совместим с более новыми версиями вашего внешнего драгоценного камня. Поскольку Ruby не позволяет переопределять предки классов, вы можете (но, пожалуйста, не делать):
- захватить содержание оригинала
/gems/impressionist-1.6.1/lib/impressionist/models/active_record/impression.rb
файл. - скопируйте его в свой
/blah/foo/impression
, - сделать ваш класс загруженным
impressionist/models/active_record/impression
в явном виде. - во второй строке файла сбрасывается оригинальный класс.
Что-то вроде этого:
require 'impressionist/models/active_record/impression'
Object.send :remove_const, 'Impression'
class Impression < LogsBase
# ORIGINAL CONTENT OF THIS FILE
end
Нет (разумного) способа переопределить базовый класс в ruby. Это возможно, но только через странные хаки.
Я бы предложил выбрать один из двух маршрутов здесь:
- Разветвите библиотеку и сделайте базовый класс настраиваемым (с обратной совместимостью).
- Не делай этого по наследству. Вместо этого положите
establish_connection ENV['SPLACER_LOGS_DB']
в модуль, иinclude
это в классе.
Я был бы склонен использовать вариант 2 на данный момент, так как это быстрый / простой обходной путь, который должен хорошо сочетаться с остальной частью приложения.