Мне очень нравится сериализация ActiveModel, особенно запутанная паутина as_json
и serializable_hash
.
В моем приложении есть большая коллекция моделей, которые разделяют поведение, включая модуль, назовем его SharedBehavior
.
Моя команда решила, что у нас есть формат по умолчанию, которому должны следовать все эти классы при приведении к JSON (для рендеринга в приложении Rails), но некоторые из них должны вести себя немного иначе. Из-за странного поведения этих двух методов из библиотеки ActiveModel добавление атрибутов из белого или черного списка в сами модели переопределяется определением метода в этом модуле, а затем передается в супердекларации в ActiveModel.
По этой причине я хотел бы, чтобы этот модуль применял свое определение этих методов к моделям только в том случае, если они явно не переопределены в этих моделях (по сути, выньте модуль из цепочки предков для нескольких вызовов методов), но я все еще нужно общее поведение из этого модуля.
Я попытался решить эту проблему, условно, динамически применяя метод включения модуля в IRB:
class A
def foo
puts 'in A'
end
end
module D
def self.included(base)
unless base.instance_methods(false).include?(:foo)
define_method(:foo) do
puts 'in D'
super()
end
end
end
end
class B < A
include D
end
class C < A
include D
def foo
puts 'in C'
super
end
end
С этим объявлением я ожидал, что вывод C.new.foo
будет
in C
in A
но это было вместо
in C
in D
in A
Моя единственная другая мысль - переместить эту логику в другой модуль и включить этот модуль в каждый класс (их около 54), который явно не переопределяет этот метод, но у этого есть пара недостатков:
- Это вводит немного неявной связи в проект, что новая модель включает этот модуль, если она не хочет переопределять реализацию этого метода.
- Текущая реализация этих методов сериализации в модуле связана с поведением и атрибутами, установленными этим модулем, поэтому я чувствую, что было бы неинтуитивно иметь второй модуль, который знает об этих деталях реализации
SharedBehavior
и зависит от них, хотя второй модуль не будет иметь почти ничего общего с первым.
Может ли кто-нибудь еще придумать другое решение или, может быть, заметить мою оплошность в приведенном выше примере кода, которая позволила бы мне сделать вызов в хуке included
? (Я также пытался изменить порядок, в котором класс C
определял метод foo
и включал модуль D
, но видел точно такое же поведение).