Open link in a new tab

Content

Expand project menu

Proper way to patching / overriding classes

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

Message actions

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