Content
Proper way to patching / overriding classes
Added by Oliver Günther over 10 years ago
In the other existing plugins, there exist several examples of patches to controllers.
However, I’m looking into porting/rewriting the git hosting plugin for OP and that requires patching the corresponding Redmine SCM adapter class.
The plugin loaded the patch through ActionDispatch::Calbacks.to_prepare
.
I’m wondering whether I can specify the patch within the registration of the plugin in engine.rb, i.e., patches [:GitAdapter]
with the patch residing under patches/git_adapter_patch.rb.
But in this case, the lookup in ActiveSupport.constantize fails for the class to be patched (Redmine::Scm::Adapters::GitAdapter), even though lib/ is currently added to autoloading in config/applications.rb
~/.rvm/gems/ruby-2.0.0-p353/gems/activesupport-3.2.17/lib/active_support/inflector/methods.rb:230:in `block in constantize': uninitialized constant GitAdapter (NameError) from ~/.rvm/gems/ruby-2.0.0-p353/gems/activesupport-3.2.17/lib/active_support/inflector/methods.rb:229:in `each' from ~/.rvm/gems/ruby-2.0.0-p353/gems/activesupport-3.2.17/lib/active_support/inflector/methods.rb:229:in `constantize' from ~/.rvm/gems/ruby-2.0.0-p353/gems/activesupport-3.2.17/lib/active_support/core_ext/string/inflections.rb:54:in `constantize' from ~/.rvm/gems/ruby-2.0.0-p353/gems/openproject-plugins-1.0.3/lib/open_project/plugins/acts_as_op_engine.rb:52:in `block (3 levels) in included' from ~/.rvm/gems/ruby-2.0.0-p353/gems/openproject-plugins-1.0.3/lib/open_project/plugins/acts_as_op_engine.rb:49:in `each' from ~/.rvm/gems/ruby-2.0.0-p353/gems/openproject-plugins-1.0.3/lib/open_project/plugins/acts_as_op_engine.rb:49:in `block (2 levels) in included' from ~/.rvm/gems/ruby-2.0.0-p353/gems/activesupport-3.2.17/lib/active_support/callbacks.rb:429:in `_run__69145852393605330__prepare__810845249135798481__callbacks' from ~/.rvm/gems/ruby-2.0.0-p353/gems/activesupport-3.2.17/lib/active_support/callbacks.rb:405:in `__run_callback' from ~/.rvm/gems/ruby-2.0.0-p353/gems/activesupport-3.2.17/lib/active_support/callbacks.rb:385:in `_run_prepare_callbacks' from ~/.rvm/gems/ruby-2.0.0-p353/gems/activesupport-3.2.17/lib/active_support/callbacks.rb:81:in `run_callbacks' from ~/.rvm/gems/ruby-2.0.0-p353/gems/actionpack-3.2.17/lib/action_dispatch/middleware/reloader.rb:74:in `prepare!' from ~/.rvm/gems/ruby-2.0.0-p353/gems/actionpack-3.2.17/lib/action_dispatch/middleware/reloader.rb:48:in `prepare!' from ~/.rvm/gems/ruby-2.0.0-p353/gems/railties-3.2.17/lib/rails/application/finisher.rb:47:in `block in <module:Finisher>' from ~/.rvm/gems/ruby-2.0.0-p353/gems/railties-3.2.17/lib/rails/initializable.rb:30:in `instance_exec' from ~/.rvm/gems/ruby-2.0.0-p353/gems/railties-3.2.17/lib/rails/initializable.rb:30:in `run' from ~/.rvm/gems/ruby-2.0.0-p353/gems/railties-3.2.17/lib/rails/initializable.rb:55:in `block in run_initializers' from ~/.rvm/gems/ruby-2.0.0-p353/gems/railties-3.2.17/lib/rails/initializable.rb:54:in `each' from ~/.rvm/gems/ruby-2.0.0-p353/gems/railties-3.2.17/lib/rails/initializable.rb:54:in `run_initializers' from ~/.rvm/gems/ruby-2.0.0-p353/gems/railties-3.2.17/lib/rails/application.rb:136:in `initialize!' from ~/.rvm/gems/ruby-2.0.0-p353/gems/railties-3.2.17/lib/rails/railtie/configurable.rb:30:in `method_missing' from ~/openproject/config/environment.rb:36:in `block in <top (required)>' from ~/openproject/config/application.rb:44:in `block in bench' from ~/.rvm/rubies/ruby-2.0.0-p353/lib/ruby/2.0.0/benchmark.rb:281:in `measure' from ~/openproject/config/application.rb:43:in `bench' from ~/openproject/config/environment.rb:34:in `<top (required)>' from ~/openproject/config.ru:32:in `block in <main>' from ~/.rvm/gems/ruby-2.0.0-p353/gems/rack-1.4.5/lib/rack/builder.rb:51:in `instance_eval' from ~/.rvm/gems/ruby-2.0.0-p353/gems/rack-1.4.5/lib/rack/builder.rb:51:in `initialize' from ~/openproject/config.ru:in `new' from ~/openproject/config.ru:in `<main>' from ~/.rvm/gems/ruby-2.0.0-p353/gems/rack-1.4.5/lib/rack/builder.rb:40:in `eval' from ~/.rvm/gems/ruby-2.0.0-p353/gems/rack-1.4.5/lib/rack/builder.rb:40:in `parse_file' from ~/.rvm/gems/ruby-2.0.0-p353/gems/rack-1.4.5/lib/rack/server.rb:200:in `app' from ~/.rvm/gems/ruby-2.0.0-p353/gems/railties-3.2.17/lib/rails/commands/server.rb:46:in `app' from ~/.rvm/gems/ruby-2.0.0-p353/gems/rack-1.4.5/lib/rack/server.rb:304:in `wrapped_app' from ~/.rvm/gems/ruby-2.0.0-p353/gems/rack-1.4.5/lib/rack/server.rb:254:in `start' from ~/.rvm/gems/ruby-2.0.0-p353/gems/railties-3.2.17/lib/rails/commands/server.rb:70:in `start' from ~/.rvm/gems/ruby-2.0.0-p353/gems/railties-3.2.17/lib/rails/commands.rb:55:in `block in <top (required)>' from ~/.rvm/gems/ruby-2.0.0-p353/gems/railties-3.2.17/lib/rails/commands.rb:50:in `tap' from ~/.rvm/gems/ruby-2.0.0-p353/gems/railties-3.2.17/lib/rails/commands.rb:50:in `<top (required)>' from script/rails:6:in `require' from script/rails:6:in `<main>'
The original plugin manually pulled in all patches and used require_dependency
beforehand to make sure the class was loaded.
Is there a way to make achieve this using the OP plugin structure?
Greets,
Oliver
Replies (1)
Hi Oliver,
at the moment, the openproject-plugins plugin only supports patches of classes that are not nested in a module. We’ll probably fix that in the future, but for now you can patch the classes manually.
You can find an example in our global-roles plugin that loads a few patches via the standard mechanism (line 36) and some others manually (line 38 and following). One of the manual patches is implemented in patches/access_control_patch.rb.
I don’t think you’ll need a manual require_dependency here, but I’m not absolutely sure, so just try without.
If you don’t like the manual patches and don’t want to wait for us, feel free to create a pull request against openproject-plugins yourself :)
Cheers,
Michael