Ну, наконец-то мы узнали, как расширить методы базового контроллера. Я опубликую это здесь так, я надеюсь, что это может быть полезно для любого, кто находит те же самые сомнения, которые у нас были. После еще нескольких исследований мы пришли к выводу, что расширение базовых контроллеров является обязательным, чтобы напрямую не изменять основные методы.
Это наши окончательные структуры каталогов / файлов:
plugins/
custom_plugin/
init.rb
lib/
custom_plugin/
issue_custom_field_patch.rb
Мы ранее заявляли, что можем использовать некоторые хуки для внедрения желаемой функциональности, но, похоже, это не работает с контроллерами. С другой стороны, мы создали патч, который расширит функциональность целевого класса.
Наш окончательный рабочий код
Init.rb
require 'redmine'
ActionDispatch::Callbacks.to_prepare do
require_dependency 'issue_custom_field'
unless IssueCustomField.included_modules.include? CustomPlugin::IssueCustomFieldPatch
IssueCustomField.send(:include, CustomPlugin::IssueCustomFieldPatch)
end
end
Redmine::Plugin.register :custom_plugin do
name 'custom_plugin'
author 'author name'
description 'description text'
version '1.0.0'
end
issue_custom_field_patch.rb
module CustomPlugin
module IssueCustomFieldPatch
def self.included(base) # :nodoc:
base.extend(ClassMethods)
base.send(:include, InstanceMethods)
base.class_eval do
unloadable
after_save :update_possible_values
end
end
end
module ClassMethods
end
module InstanceMethods
def update_possible_values
self.reload
updatedPossibleValues unless self.name == "Target_CF"
end
private
def updatedPossibleValues
@safe_attrs = ['project', 'description', 'due_date', 'category', 'status', 'assigned_to', 'priority', 'fixed_version', 'author', 'lock_version', 'created_on', 'updated_on', 'start_date', 'done_ratio', 'estimated_hours', 'is_private', 'closed_on']
@custom_fields = IssueCustomField.all.select {|cf| !cf[:position].nil?}.collect {|cf| cf.name}
@possible_values = @safe_attrs + @custom_fields
CustomField.find_by_name("Target_CF").update possible_values: @possible_values
end
end
CustomField.send(:include, IssueCustomFieldPatch)
end
Объяснение функциональности
Как мы указали в вопросе, нам нужно было обновлять возможные значения Target_CF каждый раз, когда пользователи создают / изменяют / удаляют настраиваемые поля из Redmine.
Мы расширенные методы экземпляра класса IssueCustomField, вызывающие нашу новую функцию updatedPossibleValues после каждого сохранения. Это включает в себя создание новых пользовательских полей и, конечно же, обновление существующих и удаление их. Поскольку мы каждый раз перезагружаем наш список возможных значений, нам приходилось контролировать, была ли его позиция нулевой. Если это так, это означает, что пользовательское поле было удалено.
Из-за окончательного действия этого патча, которое является обновлением другого настраиваемого поля, это также вызвало нашу функцию, вызвав бесконечное l oop. Чтобы предотвратить это, мы связали нашу функциональность с любым другим настраиваемым полем, имя которого не было «Target_CF». Немного ржавое исправление, но мы не смогли найти лучший подход.
Я надеюсь, что это может пригодиться кому-то в будущем, так как они могли бы потратить часть времени, которую мы потратили на это. Комментарии, исправления и улучшения приветствуются.
Основано на: https://www.redmine.org/projects/redmine/wiki/Plugin_Internals, которое немного устарело, но в итоге может дополнить код с помощью других ресурсов и форумов.