Posted: April 23rd, 2009 | Author: Daniel Higginbotham | Filed under: Uncategorized | 1 Comment »
FiveRuns Tuneup for Merb didn’t work out of the box for me. The following patch to the gem got it working:
Patch for Fiveruns Tuneup on Merb 1.0.11
diff -r fiveruns_tuneup_merb-0.5.3/lib/fiveruns_tuneup_merb/instrumentation.rb fiveruns_tuneup_merb-0.5.3.updated/lib/fiveruns_tuneup_merb/instrumentation.rb
170c170
< FiverunsTuneupMerb::Instrumentation.format_sql(query, adapter.send(:update_statement, query), attributes),
---
> FiverunsTuneupMerb::Instrumentation.format_sql(query, adapter.send(:update_statement, attributes.keys, query), attributes),
diff -r fiveruns_tuneup_merb-0.5.3/lib/fiveruns_tuneup_merb.rb fiveruns_tuneup_merb-0.5.3.updated/lib/fiveruns_tuneup_merb.rb
5,6c5,6
< load_dependency 'merb-slices'
< load_dependency 'fiveruns_tuneup_core'
---
> load_dependency 'merb-slices', nil
> load_dependency 'fiveruns_tuneup_core', nil
Posted: April 8th, 2009 | Author: Daniel Higginbotham | Filed under: Uncategorized | 3 Comments »
Overview
I’ve been trying to make merb a little bit easier to use by implementing form element classes. The approach I’ve taken is influenced by my experience with Cocoa. The view classes I’ve created encapsulate behavior for displaying complex form elements and for parsing the data sent to controllers by the form elements.
One great advantage that Cocoa development has over web development with an MVC framework like merb is that your views are first-class objects and can be communicated with directly using the same language as the rest of the system. With a web app, you have to go to extra lengths so that your Model or Controller will correctly get data from a form element if the element is even slightly complex. Most likely you’ll need to use Javascript in addition to whatever backend language you’re using. You’ll probably also have a lot of code to parse those elements in your controllers, spreading the concept your form element represents all over the place. In Cocoa, interacting with complex “form elements” is easier and cleaner.
Brief Cocoa Example
One iPhone app I’m on working on stores a time interval in seconds. Since it’s not very user-friendly to make a user figure that out, I use a picker that allows him to specify days, hours, and minutes.

This picker is an instance of a subclass of UIPickerView, which means it’s a first-class object and I can define methods on it to get at its tasty insides. The advantage here is that methods that belong together conceptually are placed together physically. The salient method is below:
picker valueInSeconds
- (NSInteger)valueInSeconds
{
NSInteger dayRow = [self selectedRowInComponent:0];
NSInteger hourRow = [self selectedRowInComponent:1];
NSInteger minuteRow = [self selectedRowInComponent:2];
NSInteger daySeconds = dayRow * 24 * 60 * 60;
NSInteger hourSeconds = hourRow * 60 * 60;
NSInteger minuteSeconds = minuteRow * 5 * 60;
return (daySeconds + hourSeconds + minuteSeconds);
}
Therefore when I’m ready to set the time interval, I just do the following:
medication.interval = [intervalPicker valueInSeconds];
From what I understand, this is all nothing special in Cocoa development.
The Web App Problem
merb (and Rails) have no mechanism for treating form elements as objects. Form elements are displayed using javascript, templates, and helpers. Then their data is sent to a controller as a hash. They’re usually parsed with code in the controller.
For example, traineo.com we have the following form elements:


For these form elements, we use javascript to change the weight input when the user clicks a radio button.
Initially, we had some code in our controller to get the “weight” value and convert it to kilograms so that we could then pass it to a model. Something like
if (params[:weight_input]["stone"])
# Convert from stone to kg
elsif (params[:weight_input]["american"])
# Convert from lbs to kg
else
# Leave as is; already in kg
This worked ok, but once we started placing the weight input fields in other forms, the code had to be improved. We could have created a method in ApplicationController for parsing date input, but it didn’t seem like good OO programming to make ApplicationController aware of and responsible for one set of form fields. Better to make a class and take advantage of Ruby’s object goodness.
Enough of my blathering - here’s the code:
merb widget
# lib/widgets/widget.rb
# Superclass for our form element "widgets"
class Widget
include Merb::GlobalHelpers
# This is necessary to include Merb::GlobalHelpers
class_inheritable_accessor :_default_builder
# These are for convenience
attr_accessor :params
attr_accessor :session
def initialize(params = {}, session = {})
self.params = params
self.session = session
end
def value
end
end
# lib/widgets/weight_input_switcher.rb
class WeightInputSwitcher < Widget
attr_accessor :attribute_name, :weight_in_kg, :unit_preference
# View methods
def setup(attribute_name, weight_in_kg = nil, unit_preference = session[:unit_preference])
self.attribute_name = attribute_name
self.weight_in_kg = weight_in_kg
self.unit_preference = unit_preference
self
end
def switcher
html = "<div class='weight_input_switcher'>"
html += weight_input("lbs")
html += weight_input("kg")
html += weight_input("st")
html += "</div>"
html
end
def weight_input
html = "<span class='weight_input #{unit_preference}'>"
html += weight_input_field
html += "</span>"
end
def weight_input_field
if unit_preference == "st"
stone, lbs = if weight_in_kg.to_i == 0
["",""]
else
weight_input_value(weight_in_kg, unit_preference).split(" st ")
end
html = text_field attribute_name, :value => stone, :name => "weight_input[stone]", :class => "weight_input_field stone"
html += "<span class='weight_unit'>stone</span>"
html += text_field attribute_name, :value => lbs, :name => "weight_input[lbs]", :class => "weight_input_field stone lbs"
html += "<span class='weight_unit'>lbs</span>"
else
value = weight_input_value(weight_in_kg, unit_preference)
html = text_field attribute_name, :value => value, :name => "weight_input", :class => "weight_input_field"
html += "<span class='weight_unit'>" + unit_preference.to_s + "</span>"
end
html
end
# Parse methods
# We kinda cheat here and use params. Need to figure out a better way to do this.
def value
if params["weight_input"]["stone"]
"#{params["weight_input"]["stone"]} st #{params["weight_input"]["lbs"]} lbs"
else
"#{params["weight_input"]} #{Units.weight_full_to_abbreviation_map[unit_preference]}"
end
end
private
def weight_input_value(weight_in_kg, unit_preference)
begin
weight_in_kg.to_display_weight_without_unit(unit_preference)
rescue
""
end
end
end
# The following is added to global_helpers.rb
def widget(klass, *args)
klass.new(params, session).setup(*args)
end
# An example of using the "Widget" to display form elements
widget(WeightInputSwitcher, :weight, @current_user.current_weight).switcher
# An example of using the "Widget" to get the value of form elements
weight_widget = widget(WeightInputSwitcher, :weight, 0, "", user[:unit_preference])
weight = weight_widget.value
So my code could use some improvement, but I think it lays some good groundwork for treating form elements as objects in Merb. Any feedback would be greatly appreciated!