Well of course not. Almost any app developer would get some codesharing here. But in a previous post I discussed how you could write single controllers and controller actions and still support multiple client types. And do it in a way that is much terser and more elegant than the standards Rails 1.2 “responds_to” method that tends to lengthen and obfuscate your controller methods.
But you can go even further than that to allow literally writing one application, with the same controller AND views to support two different client – something I hadn’t seen done before. Leveraging some of the magic of Rails and RXML templates combined with our own Rails helper functions we’ve done just that. For example, the CheapGas app (which I worked on quite a bit personally as a “demo app” before its release) does this: just one controller and view for the app whether its delivered as WAP or HTML or to the Mobio rich client runner.
The way that we do this is to both use RXML templates and also replace the standard HTML tag helper library (which contains functions for creating dropdown boxes, input fields, forms, and so on) with equivalent functions that generate either WAP code, XHTML tags, or tags to our own runner, depending on what kind of device is accessing it. The example .RXML template for the CheapGas search page (which supports our runner, WAP and even XHTML from just one Rails controller and view) is shown below.
xml=doctype(xml) do |x|
xml.head { }
body(x) do |x|
action="station/list"
form(action,x) do |x|
xml.p 'Search by gas stations by named location or zip code'
xml.table do
fields=[]
xml.tr do
xml.td { xml.text 'Select location '}
xml.td { xml << select_tag("location",options_for_select(@locations)) }
xml.td {xml << link_to("<small>(Manage locations)</small>", :controller=>"location")}
fields << "location"
end
xml.tr do
xml.td { xml.text 'Or supply zip code ' }
xml.td { xml <<text_field_tag('zip')}
fields <<"zip"
end
xml.tr do
xml.td { xml.text 'Within radius of '}
xml.td {
xml << text_field_tag('radius',"style1")
xml.text 'miles'
fields <<"radius"
}
end
xml.tr do
xml.td { xml.text 'Only prices within last '}
xml.td { xml << text_field_tag('filtertime')}
fields= "filtertime"
end
xml.tr { xml.td {submit_tag('Search',action,fields,x)} }
end # table
end # form
end # body
end #doctype
.RXML templates such as the one above let the Rails view be generated as code, instead of the sometimes awkward mixture of tags and code, which of course would then tie the view to a concrete set of tags. Once its all code then “smart helper functions” (select_tag(), text_field_tag(), submit_tag(), form(), body(), head() and doctype()) can be used to generate the tags for each client ype. These functions use the “client type” variable (populated with a Rails :before_filter function as described earlier) to generate the appropriate the appropriate underlying tag output over the wire. The HTML generation is straightforward. Generating WAP and our own rich client tags is more involved.
The result for the app developer is one set of code, both controller and views, to deliver multiple output types. This is something I haven’t seen in Rails apps (or other apps for that matter) whether its targeting mobile scenarios or otherwise.
Just what it means to generate tags which generate our rich client interfaces (i.e. what is the output if the client type is “Mobio Runner”) is the subject of several future posts.
May 14, 2008 at 4:14 pm
Nice.
I alsolike the idea of one appl that can get deployed to multiple clients on mobile/web – like Xforms and ZK-ish
Interested in hearing more.
Lal