Skip to content

Where to put your code

Put all customer-specific code in one plugin named modification_<name>, for example modification_acme, in plugins/easyproject/easy_plugins/.

An Easy8 update replaces the platform, the standard plugins and the engines, so changes made there are lost. Your modification_* plugin is not part of Easy8: carry it over to each new version. Easy8 always activates it and loads it after its own plugins.

What the plugin contains

Easy8 treats a directory in plugins/easyproject/easy_plugins/ as a plugin when it has a lib/ directory or a Gemfile. Everything else is optional and picked up by convention:

plugins/easyproject/easy_plugins/modification_acme/
  lib/modification_acme.rb         # required by the plugin loader, may be an empty module
  config/initializers/*.rb         # permissions, menus, hooks, settings
  config/routes.rb                 # routes of the plugin
  config/locales/*.yml             # translations
  app/controllers, app/models,     # autoloaded, one constant per file
  app/views, app/helpers, ...
  patches/**/*.rb                  # changes to existing classes
  db/migrate/, db/data/            # migrations
  test/spec/                       # specs

Minimal lib/modification_acme.rb:

module ModificationAcme
end

How each part is loaded:

  • config/initializers/*.rb are required when Easy8 starts. Use EasyInitHelper for permissions, menus and view hooks, see EasyInitHelper. Existing plugins such as easy_buttons split them into 01_access_control.rb, 02_menu_manager.rb and 03_hooks.rb.
  • config/routes.rb is plain routes DSL, without Rails.application.routes.draw.
  • config/locales/*.yml are added to the I18n load path.
  • app/views is added to the view path. Prefer your own controllers and views. To add a small part to an existing view, use a view hook.
  • Files in patches/ are required at boot. Register each patch with EasyPatchManager, see Patches.
  • bundle exec rails easy8:install runs db/migrate and db/data of the plugin. Follow the migration rules.

What not to change

Do not edit files in the Redmine core, in easy_engines/ or in other plugins. To change their behaviour, patch them from your plugin.

Every change outside your plugin must be re-applied after each update, and a merge conflict is likely.

Deploy the plugin

Docker installation

Keep the plugin folder next to docker-compose.yml and mount it into the app and sidekiq containers with a docker-compose.override.yml in the same folder. Docker Compose reads the override file automatically, and an Easy8 update does not replace it.

services:
  app:
    volumes:
      - ./modification_acme:/opt/easy/current/plugins/easyproject/easy_plugins/modification_acme:ro
  sidekiq:
    volumes:
      - ./modification_acme:/opt/easy/current/plugins/easyproject/easy_plugins/modification_acme:ro

Run the plugin's migrations and restart Easy8:

docker compose run --rm app install
docker compose up -d
  • The containers run as user 5000, so that user must be able to read the plugin files.
  • If you start Easy8 with -f options, Compose does not load the override file by itself; add -f docker-compose.override.yml.
  • The image contains precompiled frontend assets. A mounted plugin can add Ruby code, views, translations, routes and migrations, but no stylesheets or scripts that Easy8 compiles. Those have to be built into the image, see Build image in the Docker guide. Branding needs no build, see Branding on Docker.

After an update, the new image picks up the same mount. Run docker compose run --rm app install again.

Source installation

Copy the plugin folder to plugins/easyproject/easy_plugins/ and run the installer:

RAILS_ENV=production bundle exec rails easy8:install

If the plugin has stylesheets or scripts, rebuild the assets with RAILS_ENV=production bundle exec rails assets:precompile, then restart Easy8. After an update, copy the folder into the new version and repeat these steps.