Managing Plugin Settings - Redmine Plugin Extension and Development (2014)

Redmine Plugin Extension and Development (2014)

Chapter 7. Managing Plugin Settings

As we continue to add features and functionalities to our plugin, the need for custom configuration also becomes more apparent. It is likely that system administrators will not need all the bells and whistles at all times, or they may need to fine-tune one thing or another. Having such flexibility results in our plugin becoming even more appealing.

Redmine provides plugin authors with tools that facilitate the process of managing plugin-specific settings, which we'll explore in this chapter.

We will cover the following topics in this chapter:

· How to initialize our plugin with settings and default values

· The configuration of the settings partial

· The use of custom settings in controllers and views

An overview of Redmine's global plugin settings

Redmine provides plugin authors with an integrated configuration system in order to simplify the management of configuration values:

An overview of Redmine's global plugin settings

Plugin settings are only available to Redmine users with administrator privileges. For these users, a summary of all plugins is available at http://localhost:3000/admin/plugins.

If a plugin has been configured to provide an administrator with a settings view, a Configure link will be available.

The information that is displayed for each plugin in the list is pulled from the name, author, author_url, description, url, and version attributes that were provided to the Redmine::Plugin.register block in each plugin's init.rb file.

Note

As of Redmine 2.3.4, which was released on November 17, 2013, the plugin settings management interface is only available for global configuration. There are no functionalities provided in order to manage custom per-project settings.

Enabling settings management

In Chapter 1, Introduction to Redmine Plugins, we were introduced to the Redmine plugin's initialization file as well as some of the attributes, methods, and helpers available to plugin authors.

The settings attribute was presented as a way for plugin settings to be initialized as well as a configuration partial view to be defined:

Redmine::Plugin.register :redmine_knowledgebase do

# ...

settings :default => {

:sort_category_tree => 1,

:show_category_totals => 1,

:summary_limit => 5,

:disable_article_summaries => 0

}, :partial => 'redmine_knowledgebase/knowledgebase_settings'

# ...

end

Our plugin's settings field is initialized with a hash that expects two keys:

· :default: This key expects a hash, which will be used to initialize our plugin's settings values to defaults that will be presented on first use. Once a configuration value has been explicitly set, the default values are no longer used.

· :partial: This holds a relative path to a partial view within our plugin that can be used to set configuration and settings values. Using the previous example of redmine_knowledgebase/knowledgebase_settings, the location of the actual partial view will be/path/to/redmine/plugins/redmine_knowledgebase/app/views/redmine_knowledgebase/_knowledgebase_settings.html.erb.

Note

A generic value (for example, settings, config) should not be used as it can potentially be overwritten by another plugin using the same name. A good approach is to place your settings partial view in a subfolder named after your plugin; in our case,redmine_knowledgebase/knowledgebase_settings.

Configuration management

The partial view we defined when initializing our plugin's settings field will be rendered when an administrator clicks on the Configure link for our plugin:

Configuration management

The partial that we'll create will be made up of a number of groups. Each group represents a settings key that we want to update a value for.

The fields that we'll define will be a subset of a predefined form, which is rendered if our plugin has defined a partial to be used for configuration. This partial is injected into the form at /path/to/redmine/app/views/settings/plugin.html.erb.

As the form tag has already been defined, all we have to provide are input tags that capture our settings, values. For this to work properly, we name the input fields settings[our_setting_name].

<p>

<%= label_tag :settings_sort_category_tree, l(:allow_sort_category_tree) %>

<%= check_box_tag 'settings[sort_category_tree]', 1, @settings[:sort_category_tree] %>

</p>

<p>

<%= label_tag :settings_show_category_totals, l(:show_category_totals) %>

<%= check_box_tag 'settings[show_category_totals]', 1, @settings[:show_category_totals] %>

</p>

<p>

<%= label_tag :settings_summary_limit, l(:summary_item_limit) %>

<%= text_field_tag "settings[summary_limit]", @settings[:summary_limit] %>

</p>

<p>

<%= label_tag :settings_disable_article_summaries, l(:disable_article_summaries) %>

<%= check_box_tag 'settings[disable_article_summaries]', 1, @settings[:disable_article_summaries] %>

<%= count_article_summaries %>

</p>

The partial we provided to the settings attribute gives us an @settings instance variable, which will provide the default value of each settings key (assuming we initialized it).

Configuration management

As we can see, the partial renders our content with a predefined heading and an Apply button. Also, we didn't have to explicitly define a form as Redmine has provided this functionality for us.

Exposing plugin methods to the settings partial

One of the settings we have is a toggle for whether article summaries should be visible.

As this feature was added after the initial introduction of article summaries, it will be useful to administrators if they could gauge how many people are actually using this feature before they disable it.

First, we'll define a method in KnowledgebaseSettingsHelper, which is located at /path/to/redmine/plugins/redmine_knowlegebase/app/helpers/knowledgebase_settings_helper.rb.

module KnowledgebaseSettingsHelper

def redmine_knowledgebase_count_article_summaries

"#{KbArticle.count_article_summaries} of #{KbArticle.count} have summaries"

end

end

For reference, the count_article_summaries method that is cited from the KbArticle model is as follows:

def self.count_article_summaries

KbArticle.where("summary is not null and summary <> ''").count

end

We'll now update our plugin settings partial to include the summary count. Once this is done, if we try to refresh the page, an error will be displayed as follows:

ActionView::Template::Error (undefined local variable or method `redmine_knowledgebase_count_article_summaries' for #<#<Class:0x000000063503f8>:0x000000066c6848>).

The issue here is that the context under which our settings partial view runs does not have direct access to our plugin's resources. As a result, none of the custom methods we have in our plugin are available at this point.

In order for Redmine to know what to do with our redmine_knowedgebase_count_article_summaries method, we'll need to include our helper as a part of Redmine's SettingsHelper.

This can be accomplished by adding the following block to our plugin's initialization file:

ActionDispatch::Reloader.to_prepare do

SettingsHelper.send :include, KnowledgebaseSettingsHelper

end

The method of mixing in functionalities is common in Ruby (and Rails). We wrap the call in a ActionDispatch::Reloader.to_prepare block (for more information, see http://api.rubyonrails.org/classes/ActionDispatch/Reloader.html#method-c-to_prepare) as we want to ensure we don't break any other plugin that can be mixing functionalities into SettingsHelper.

Once this is done and our application has been restarted, our plugin settings page will be rendered correctly.

Exposing plugin methods to the settings partial

Note that by injecting our own functionalities into Redmine's SettingsHelper, there's always a chance that we'll override core methods due to identical naming conventions.

As such, it's a good practice to create a separate helper file with only the functions that need to be included in the settings helper and ensure that the methods we include are prefixed such that they stand out as belonging to our plugin.

Accessing our settings

Redmine's Setting model can be used to retrieve the settings values that we've configured.

The Setting model is used internally by Redmine to manage all internal settings. Since the actual values that are being stored are YAML-encoded, they can be more complex than simple strings or integers. The structure of a Setting entry is as follows:

Setting(id: integer, name: string, value: text, updated_on: datetime)

When accessing a plugin settings value, we need to provide the internal name of the setting as well as the key of the specific settings value we want to retrieve. This request takes the following form:

Setting['plugin_redmine_knowledgebase'][key]

The naming convention used is plugin_#{plugin.id} as this is how Redmine internally manages plugin settings (for more information, see /path/to/redmine/app/models/setting.rb).

In the previous section, we discussed the disabling of article summaries if the administrator sets the appropriate toggle in our plugin's configuration. The following screenshot is an example of a category list that includes an article with a populated summary:

Accessing our settings

Although we've already covered capturing and storing the settings value needed to disable article summaries, in order to apply this setting to our views, we need to include a basic value check. This can be done as follows:

<% unless Setting['plugin_redmine_knowledgebase'][:disable_article_summaries] %>

<br/>

<div class="summary">

<%= article.summary %>

</div>

<% end %>

Now Redmine will check our global settings before trying to display article summaries when browsing a category.

Note

Although the preceding example illustrates how we can check settings values in our views, the process is identical from within our controllers.

Summary

As our plugins evolve and grow, the number of features will grow as well. Since not all functionality is required in every deployment, allowing administrators to toggle features on and off will make our plugins much more useful for a larger number of installations.

In this chapter, we learned how to take advantage of the built-in settings management functionalities of Redmine and how we can leverage it for our plugins.

In our next chapter, we'll introduce the topic of testing our plugins.