Project

General

Profile

How to Monkey Patch a Model in a Core from a Plugin

Added by Ben Wheeler over 9 years ago

I'm wondering how to monkey patch the watcher model from my plugin.

Running v2.5.2 of Redmine:

RAILS_ENV=development ruby script/rails server webrick -e development

My model looks like this:

class WatcherWeight < ActiveRecord::Base
  belongs_to :watcher
end

I want my model's objects to delete when a watcher is deleted, so my patch looks like:

class Watcher < ActiveRecord::Base
  has_one :watcher_weight, dependent: :destroy
end

And in my plugin's init.rb I have this:

ActionDispatch::Callbacks.to_prepare do
  #patches
  Rails.logger.debug 'WATCHLIST: hello world'
  require_dependency 'watcher'
  require_dependency 'plugins/watchlist/lib/watcher_patch'
end

The problem is that my code only runs when my controller handles the response, not all the time (e.g. I need it to run on DELETE "/issues/{issue_id}/watchers/{watcher_id}" request.

Please let me know the best way to do this. This is my first time writing ruby at all let alone a rails/redmine plugin...


Replies (3)

RE: How to Monkey Patch a Model in a Core from a Plugin - Added by Martin Denizet (redmine.org team member) over 9 years ago

Hello Ben,

Your patch should look like:

module MyPlugin
  module Patches
    module WatcherPatch
      def self.included(base) # :nodoc:

        base.send(:include, InstanceMethods)

        base.class_eval do
          unloadable # Send unloadable so it will not be unloaded in development
          has_one :watcher_weight, dependent: :destroy
        end
     end
   end
end
Watcher .send(:include, MyPlugin::Patches::WatcherPatch)

Let me know if it works,

Cheers,

RE: How to Monkey Patch a Model in a Core from a Plugin - Added by Ben Wheeler over 9 years ago

Hi Martin,
Awesome! I cribbed off of the redmine_helpdesk plugin and figured out the above, but I was missing the "unloadable" keyword! That was the ticket.

My code now looks like this:

module Watchlist
  module WatcherPatch
    def self.included(base) # :nodoc:
      base.send(:include, InstanceMethods)

      base.class_eval do
        unloadable
        has_one(:watcher_weight, :dependent =&gt; :destroy)
        after_create :addWatcherWeight
      end
    end

    module InstanceMethods
      def addWatcherWeight
        WatcherWeight.create(:watcher_id =&gt; id, :weight =&gt; 0)
      end
    end

  end # module WatcherPatch
end # module Watchlist

# Add module to Watcher class
Watcher.send(:include, Watchlist::WatcherPatch)

The only problem I'm having now is my watcher_weight record still does not get automatically deleted when the parent watcher record is destroyed. I thought this line should take care of that:

has_one(:watcher_weight, :dependent => :destroy)

What am I missing?

RE: How to Monkey Patch a Model in a Core from a Plugin - Added by Ben Wheeler over 9 years ago

I figured out that the watchable plugin calls delete_all rather than destroy, which doesn't honor :dependent => :destroy.

    (1-3/3)