Redmine Plugin Development - Part1: Generation, Enumerations, Hooks
Posted by Sergey Enin 09 April 2011 at 02:40
Currently redmine represents good and powerfull project management system.
It`s free, powerfull and provide a lot customization and extensable features. Third-party features is rational to implement through plugins, than change the core code, - it is avoid problems when others in your team also would like to customize redmine or when you would like update your instance in future.
Especially great that redmine shows how ruby metaprogramming phylosophy transforms into great solution.
I created for myself little manual, where I described all most interested or obscure questions I faced during work with redmine, separated into 2 parts:
1) Generation, Enumerations, Hooks.
2) Customization.
Below is Part 1.
Please, consider, that I will not cover points that good is on Plugin Page.
Generation
To create plugin you need to
ruby script/generate redmine_plugin
so,
rails generate redmine_plugin Polls
create vendor/plugins/redmine_polls/app/controllers create vendor/plugins/redmine_polls/app/helpers create vendor/plugins/redmine_polls/app/models create vendor/plugins/redmine_polls/app/views create vendor/plugins/redmine_polls/db/migrate create vendor/plugins/redmine_polls/lib/tasks create vendor/plugins/redmine_polls/assets/images create vendor/plugins/redmine_polls/assets/javascripts create vendor/plugins/redmine_polls/assets/stylesheets create vendor/plugins/redmine_polls/lang create vendor/plugins/redmine_polls/README create vendor/plugins/redmine_polls/init.rb create vendor/plugins/redmine_polls/lang/en.yml
It is creates by default plugin with name: redmine_polls, if you dont want to see prefix redmine_ you can: 1) rename plugin folder; 2) in plugin folder/init.rb raname to new plugin name also; and it`s done
Regarding auto created lang directory -
The location of *.yml translation files, depends on redmine version:
Version Path
|
< 0.9 |
|
|
>= 0.9 |
|
Generation of controllers, models and migrations casuals, but you need to rename migrations from timestamp to numbers format.
If you want to migrate specific plugin to version X(for example uninstall specific plugin) you can just:
rake db:migrate:plugin NAME=redmine_products VERSION=0
Enumerations
Enumeration is example of rails STI(single table inheretance).
The casual way of adding your own Enumeration` STI child is:
1) in init.rb of your plugin:
require 'dispatcher'
#Hack to add STI ProductSource to subclasses of Enumeration
Dispatcher.to_prepare do
require_dependency 'enumeration'
require_dependency 'product_source'
end
2) in app/models/product_source.rb:
require_dependency 'enumeration'
class ProductSource < Enumeration
OptionName = :product_source_categories
def option_name
OptionName
end
end
3) so, in console:
ruby-1.8.7-p302 > ProductSource.first
=> ProductSource id: 15, name: "Commercial", position: 1, is_default: true, type: "ProductSource", active: true, project_id: nil, parent_id: nil
ruby-1.8.7-p302 > Enumeration.find(15)
=> ProductSource id: 15, name: "Commercial", position: 1, is_default: true, type: "ProductSource", active: true, project_id: nil, parent_id: nil
This way works in production and work in development mode only for first loading of init.rb, this connected with Dispatcher.to_prepare, cause by definition:
Dispatcher.to_prepare(identifier = nil, &block)
Add a preparation callback. Preparation callbacks are run before every request in development mode, and before the first request in production mode. An optional identifier may be supplied for the callback. If provided, to_prepare may be called again with the same identifier to replace the existing callback. Passing an identifier is a suggested practice if the code adding a preparation block may be reloaded.
Source: on GitHub
So, when you will try to reload page in development mode, you will have error, like:
Sun Apr 10 17:04:52 +0300 2011: Read error: #TypeError: superclass mismatch for
class ProductSource
redmine/vendor/plugins/products/app/models/product_source.rb
:2
In one of the next articles I will review this more detaily and will try to propose some solutions.
Hooks
Hooks is way of insert your own logic into redmine core code, that was provided by redmine developers through inserting special hooks code.
There are 3 types of hooks in redmine:
1) View hooks;
2) Controller hooks;
3) Model hooks;
Read next part of guide: Redmine Plugin Development - Part2: Journal, Customization of Redmine Menu and Core
Links:
- Redmine - http://www.redmine.org
- Redmine - Developers Guide http://www.redmine.org/projects/redmine/wiki/Developer_Guide
- Redmine - Plugin Tutorial http://www.redmine.org/projects/redmine/wiki/Plugin_Tutorial
- GitHub of Redmine creator with a lot of ready plugins http://github.com/edavis10

