Refactoring Changes

Goal

Currently, lots of our redmine changes are patched into the redmine core, making it difficult to update. I'd like to extract as many changes as possible into plugins.

Extend application.rb

We need the "MenuGeneratorHelper" which is supplied as a plugin. This helper is used in the template, that's why I added the following code to application.rb:

helper MenuGeneratorHelper

Override the method set_localization in application.rb:

We want to disable the automated language guessing based on the HTTP_ACCEPT_LANGUAGE

   def set_localization
     User.current.language = nil unless User.current.logged?
-    lang = begin
-      if !User.current.language.blank? and GLoc.valid_languages.include? User.current.language.to_sym
-        User.current.language
-      elsif request.env['HTTP_ACCEPT_LANGUAGE']
-        accept_lang = parse_qvalues(request.env['HTTP_ACCEPT_LANGUAGE']).first.split('-').first
-        if accept_lang and !accept_lang.empty? and GLoc.valid_languages.include? accept_lang.to_sym
-          User.current.language = accept_lang
-        end
-      end
-    rescue
-      nil
-    end || Setting.default_language
+#    lang = begin
+#      if !User.current.language.blank? and GLoc.valid_languages.include? User.current.language.to_sym
+#        User.current.language
+#      elsif request.env['HTTP_ACCEPT_LANGUAGE']
+#        accept_lang = parse_qvalues(request.env['HTTP_ACCEPT_LANGUAGE']).first.split('-').first
+#        if accept_lang and !accept_lang.empty? and GLoc.valid_languages.include? accept_lang.to_sym
+#          User.current.language = accept_lang
+#        end
+#      end
+#    rescue
+#      nil
+#    end || Setting.default_language
+     lang = Setting.default_language
     set_language_if_valid(lang)    
   end

Adjust projects_controller.rb

Because we have an ajax autocompleter for the usernames in the project settings, the following diff needed to be made:

-  menu_item :settings, :only => :settings
+  menu_item :settings, :only => [ :settings, :auto_complete_for_user_login ]

-  before_filter :authorize, :except => [ :index, :list, :add, :archive, :unarchive, :destroy, :activity ]
+  before_filter :authorize, :except => [ :index, :list, :add, :archive, :unarchive, :destroy, :activity, :membershiprequest, :auto_complete_for_user_login ]

We needed a new method to handle the "new membership request"

Extend models/mailer.rb

We want to send out emails on project membership request

Override views/account/show.rhtml

... and other views

Override layouts/_base.rhtml

(the main template)


Ruby, Rails, Redmine and overloading

In Ruby it is possible to reopen classes at runtime. So you can reopen every existing class and override a method or add additional functionaltiy at any time. By that means, that overriding stuff in Rails should be easy.
It actually is... but with a major problem.

It's all about the order of loading parts in Rails. Deduced from this article, Rails does the loading of parts in this order:

Rails => Plugins/Engines => the app in /app/...

So the plugins are loaded first (which absolutly makes sense) and the app/ folder is last. That means, that you can't override functionality written in the app/ folder from within a plugin. Instead you can override methods of a plugin with methods placed in the app/ folder.

Overloading Redmine

Not tested yet, but this could be an approach: Put the redmine app/ folder (and maybe the lib/ folder too) in a new engine-plugin and override the Redmine model/controlers/views from within the app/ folder. There may be problems with dependencies, the order of loading plugins etc..

ToDo: Check this out on a local forge instance.