Content
After the fork, we started a big migration project to get OpenProject up to speed with the current state of Rails.
Migrating OpenProject to Rails 3 (and Rails 4)
After the fork we now have full control over all technical aspects of OpenProject, which gives us the opportunity to rethink everything and to make changes to the entire code base. In particular, we are now free to make internal changes to the core component.
First things first, we wanted to prepare the existing code base for the enhancements and new features we’re planning. One of the most obvious things to do then, was to migrate OpenProject to a more recent Rails version. At the time of the fork Redmine and Chiliproject were still based on Rails 2. When we started the migration, Rails 4 wasn’t ready yet although close to a release. Rails 3 however has been out for a while (since 2010 actually and Rails 3.2 since 2012). Upgrading from Rails 2 to Rails 4, while skipping version 3 entirely is not a recommended upgrade path, so we decided to upgrade to stable Rails 3 first and then move to Rails 4 later.
OpenProject plugins
The core component of OpenProject is a typical Rails app, which made the migration steps pretty clear: We had to update all deprecated components, rewrite changed syntax, routes etc.. The differences between Rails 2 and Rails 3 were considerable and often we included some refactorings and bug fixes along the way in our migration. In addition, we now fully support the Rails 3 asset pipeline.
A major (and growing) part of OpenProject however is its plugin ecosystem. Redmine and Chiliproject plugins are implemented as Rails2-style plugins, a concept that has been deprecated in Rails 3.2 and will be removed entirely in Rails 4. For our migration, we took the time to to think about how to migrate existing plugins and how to find a sustainable solution that will be both easy to maintain and to deploy.
Moving all plugin code to the /lib-folder of OpenProject instead of the deprecated /vendor/plugins folder would have been the simplest solution to keep everything working in Rails 3. However, this would be a tedious process for users who want to install or update OpenProject plugins. It’s just a workaround rather than a solution and would lead to an unintuitive, non-standard application structure. The new way of extending Rails apps with custom components is through either regular Ruby gems or Rails engines (http://guides.rubyonrails.org/engines.html), which are usually bundled as gems, too. Rails 3 supports two different kinds of engines:
- Full engines - This type of engine integrates all code directly into the host app, its routes are added to the host application.
- Mountable engines - This type of engine can be ‘mounted’ in the host app under an url by adding it to the routes file of the host app. Its code is usually isolated in its own module namespace.
For our plugins, full engines were the preferred approach, because the code often adds functionality, view, routes etc. to different parts of the application or changes behavior of existing code. In most cases, it’s not functionality that could easily be isolated from the host application and accessed under a separate URL.
What actually turns the gem into an engine, is the ‘engine.rb’ file, which is responsible for
- Registering the gem as an engine and adding the app code and routes to the host application.
- Adding Assets to the pipeline
- Loading Patches & Hooks
- Registering the plugin in OpenProject (to make it appear in plugin settings)
- Executing Custom initializers
These steps are found in all OpenProject plugins, so we moved all common code to the new openproject-plugins gem (https://github.com/opf/openproject-plugins). Additionally, this gem includes a generator that creates a basic plugin structure that you can use to develop new OpenProject plugins. Read the annoucement here: https://www.openproject.org/news/26
All plugins now follow the standard gem structure with a .gemspec and will be made available on Github (www.github.com/finnlabs) and RubyGems (http://rubygems.org/).
Future plans
As Rails 4 has been released in the meantime, we took care to plan our migration so that a future upgrade to Rails 4 will be as smooth as possible. For example, we are already using the ‘strong parameters’ feature that’s coming in Rails 4 (http://guides.rubyonrails.org/action_controller_overview.html#strong-parameters) . And with our gem and engine based architecture we have laid a solid foundation for coming updates.
Also, our solution will make it easy for users and newcomers to OpenProject to deploy and change their configuration: Just add any plugins you’d like to use to the Gemfile of OpenProject, copy and run migrations (if any) with Rake and you’re done.
Ruby version 2.0 has been released as well in the meantime and is the recommended Ruby version for Rails 4. We are currently running our OpenProject Beta with Ruby 2.0 in development environments and haven’t run into any serious problems with it yet. 2.0 is highly compatible with 1.9 and we’re planning to make Ruby 2 the official, recommended Ruby version for OpenProject soon.
And as you probably know, we’re now constantly releasing and open-sourcing OpenProject plugins for our OpenProject Beta. Check our news section regularly for updates!
Comments
Thanks to all contributors and sponsors of this big task!