BoilerPlate is a framework on top of Ruby on Rails that is intended to make development of data-centric applications as easy as possible.
Some technicalities can be found in the README. For the scenic route, see below.
By now, BoilerPlate itself has died, but it lives on in a few plugins that I've published. Please see my page at RubyForge.
Being in its early childhood, BoilerPlate is still rather browser shy. It looks and works as intended in Mozilla Firefox and Konqueror. In Internet Explorer it will probably present itself as an angry fruit salad with bad manners.
Currently, I can't host a live demo. To overcome this a bit, I've set up a couple of static demo pages. These are essentially saved versions of pages generated by the demo application. I have tweaked them somewhat to avoid the most egregious errors, but they will contain dead links and produce errors on some actions. For the list views, client-side column reordering is switched on; normally this is done on the server.
Here's all the code from app/views/tasks/list.rhtml needed to create this view. No need to write it yourself as it gets generated.
<% @page_title = 'Tasks' %> <div id="entitylist"> <%= render :partial => 'shared/entity_list' %> </div>
Well, okay, that's not all. The controller needs to support it somewhat:
class TasksController < ApplicationController
layout :standard_layout
define_list_action :list, Task,
{ :path => 'description', :inline => '<%= truncate(object, 30, BoilerPlate::Unicode::Constants::HORIZONTAL_ELLIPSIS) %>'},
{ :path => 'due_date', :partial => 'shared/short_date'},
{ :path => 'category.name', :title => _('Category'), :type => :string, :include => :category },
{ :path => 'status.name', :title => _('Status'), :type => :enum, :include => :status }
...
end
Beyond that, however, you don't need any more code.
Table columns can be reordered by drag & drop.
Filter the displayed rows by certain criteria.
A form for creating a new object. Input elements with (client-side) validation errors are marked red(ish).
The code for app/views/employees/_form.rhtml:
<!--[form:employee]-->
<%= labeled_text_field 'employee', 'lastname', :label => _('Last name'),
:validation_message => _('Please enter a last name in this field.') %>
<%= labeled_text_field 'employee', 'firstname', :label => _('First name'),
:validation_message => _('Please enter a first name in this field.') %>
<%= labeled_gender_choice 'employee', 'gender',
:validation_message => _('Please choose one option.') %>
<% collapsible_fieldset(:legend => _('Address'), :except => 'new', :valid => @address) do %>
<%= render :partial => 'shared/address', :object => @address %>
<% end %>
<%= labeled_association_target_chooser 'employee', 'manager', { :label => _('Managed by') }, :action => :manager_candidates %>
<% collapsible_fieldset(:legend => _('Assigned Tasks'), :only => 'new') do %>
<%= association_targets_chooser_with_query 'employee', 'tasks', :text_method => :description, :action => :task_candidates %>
<% end -%>
<%= version_lock 'employee', 'address' %>
<!--[eoform:employee]-->
Code for new.rhtml and edit.rhtml is generated.
Choose an associated object. There's AJAX in there...
No extra code is required in the controller to handle this.
With optimistic locking there's always the possibility of conflicts. Some other user may have changed or deleted an object just while you're editing it yourself. BoilerPlate tells you when this has happened and allows you to clean up the conflict.
There's nothing spectacular in the form itself.
<!--[form:task]-->
<%= labeled_calendar_field 'task', 'due_date', {}, :class => 'mandatory' %>
<%= labeled_text_area 'task', 'description', {}, :rows => 5 %>
<%= labeled_select 'task', 'status', :class => 'mandatory' %>
<%= labeled_tree_navigator 'task', 'category', {}, :initially_collapsed => (@action_name == 'edit') %>
<%= version_lock 'task' %>
<!--[eoform:task]-->
And the code in the controller looks pretty easy, too.
def update
@task = Task.find(params[:id])
result = update_optimistically(@task, params[:task])
handle_update_result(result, [:task])
end
The code above already contains the tree navigator. In the screenshot above it is collapsed; below is what it looks like when expanded. Levels are loaded dynamically via AJAX requests.
The controller needs this bit of code to service the request.
define_ajax_action :child_categories, Category, {
:conditions => [ 'parent_id = ?' ],
:condition_values => [ :id ],
:partial => 'categories',
:default_response => ' '
}
I'm Michael Schürig, a software developer located in Bonn/Germany. If you'd like to get an idea of what I do and what I'm interested in, please visit my home page. Available for hire.