The idea for this HOWTO is based on the request [#141] where a user suggested to use a project drop-down to be able to switch between projects more efficiently.
Based on the attached patch (thanks, Kou) I put together a short step-by-step recipe for extending existing Retrospectiva with additional functionality without touching the core. The resulting code adds a simple project drop-down at the bottom of the page, it can be found here:
We want to add something into the page footer, so let’s find out how the footer is rendered. By looking into app/views/layouts/_footer.rhtml we can see that the left part of is rendered by a helper method called @render_left_side_footer, which can be found in app/helpers/application_helper.rb.
By looking closer we can see, that this method contains 3 extendable interfaces:
elements += view_extensions(:footer, :left, :before, :join => false)
...
elements += view_extensions(:footer, :left, :between, :join => false)
...
elements += view_extensions(:footer, :left, :after, :join => false)
First, we create a directory in the extensions folder, in our case: extensions/project_drop_down. Next, we create a view-partial that will store the extension code:
01: <% if Project.current && User.current.projects.size > 1 -%>
02: <span class="quiet">
03: <%=_ 'Projects' %>
04: <select onchange="window.location.href=this.value;">
05: <%
06: choices = User.current.projects.map do |project|
07: [h(project.name), project_path(:project_name => project.short_name)]
08: end
09: selected = project_path(:project_name => Project.current.short_name)
10: -%>
11: <%= options_for_select choices, selected %>
12: </select>
13: </span>
14: <% end -%>
select tag, which contains a JS callback to follow the right URL on-change.All partials need to be saved within the view directory in the extension folder. Partial paths need to be unique across all extensions, therefore it makes sense to save it in a nested folder structure that includes the extension name, i.e. (in our case) extensions/project_drop_down/views/project_drop_down/_footer.html.erb.
In our application_helper.rb we had the following line: view_extensions(:footer, :left, :between, :join => false), remember? Let’s assume we want our partial appear at this position of the page footer, we need to create the ext_info.rb file in our extension directory with the following content:
RetroEM::Views.register_extension('project_drop_down/footer', :footer, :left, :between)
The ext_info.rb is loaded once (together with the plugin), in our case we associate the relative partial path project_drop_down/footer with the [:footer, :left, :[between] extension interface slot, where it will appear when the page is loaded.
To install the plugin, we simply call ruby script/rxm project_drop_down. Done!
The only thing that can still be improved is the partial. Lines 5-11 contain processing logic, which is not only bad practice but also quite messy and difficult to read. How about externalising this bit into a nice and simple helper method? No problem at all, we just need to extend application_helper.rb. To do so, just create a file ext/application_helper.rb file and add the helper method (i,e. options_for_project_drop_down) to it. Now just change the partial to use the helper method instead of the messy inline code and … enjoy!
Do you want to create an extension and require more interfaces? Just file a ticket and I will extend the core with the additional requirements.