onrails.org home

Flex Dynamic Scaffolding for Ruby on Rails.

No I am not announcing the next killer scaffolding framework but I had a couple of hours available today so I just explored some of the cool features or Ruby On Rails and Flex. The part I was most interested in (today) is dynamic user interface creation and not generating and application like several scaffolding frameworks are doing. So I was able to create a UI that adapts to a given model of a Rails application. Of course I didn’t go as far as I wished, but I thought I could share it with my readers as I usually get valuable feedback. Right now the application doesn’t even manage data. That will be the next step.

20070804_FlexScaffolding.jpg
In a first phase I have adapted RaildRoad Rails model class diagram generation tool to generate an xml definition that the UI would use to create it’s components. I generated an xml model for Sports a sample application provided with Streamlined and Typo a blog server.

The UI generation from the typo model is quite cpu intensive. There is not lazy instanciation of components, when you select the model, all the Tabs, lists and forms are created.

You can run the application and press view source from the context menu. Or you can see the source here. The generated xml can be seen here and here

In a second phase I created a Flex application that generates a UI from the given xml.

I was writing this blog entry while coding, so if you are more curious about how all this works, keep on reading.

Getting the schema of your ActiveRecords

We will generate an xml version of the schema that Flex can use to assemble a UI. So we need to find out info about each ActiveRecord of the application, it’s association with other ActiveRecords, and all it’s attributes. Later on would also be nice to identify the validation rules, so that we can build some validations on the fly without having to do a server round trip for some of the basic validations, (required, length, confirmation, regex). Supporting the various acts_as could also provide lots of functionality that doesn’t need to be coded over and over.

I will use the Streamlined Sports example database to experiment with. Later on we may have a look at Typo a blog server.

Let’s use the community to see how to parse the ActiveRecord. I am now checking out RailRoad (0.4.0) a class diagram generator for Rails. Railroad has the ModelsDiagram class that gather the information we need and then uses the DiagramGraph class to generate a dot format file that in turn is used to generate .svg or .png of the diagram. We are not interested in the dot generation, but will just ‘adapt’ the to_dot method to get the xml we need. So I simply reopened the class and created a new to_dot method as follows:

  1. http://chadfowler.com/2007/8/3/enumerable-injecting
    module Enumerable
    def injecting(s)
    inject(s) do |k, i|
    yield(k, i); k
    end
    end
    end

class DiagramGraph

def to_dot return definition.to_xml(:root => ‘active_records’, :dasherize => false) end #Let organize the data in a way closer to the xml we want to generate. def definition active_records = {} @nodes.each do |node| attributes = node2.injecting({}) {|accumulator, value| k,v=value.split(" :"); accumulator[k] = v} class_name = node1 active_records[class_name] = { :name => class_name, :attributes => attributes, :relations => [] } end @edges.each do |edge| association_type = edge0 from_class_name = edge1 to_class_name = edge2 active_records[from_class_name][:relations] << {association_type.to_sym => to_class_name} end active_records end

end

The definition method generates a hash map with the information of the model. The to_xml is all that is needed to get an xml version of the data that the map contains.

definition.to_xml(:root => ‘active_records’, :dasherize => false)

Dynamically Generate a Flex UI

Let looks at the model.

Player has_many Sponsor
Coach has_many Sponsor
Team has_one Coach
           has_many Player
Sponsor has nobody!

The UI generation should be lot smarter and configurable. For now I have taken the approach to create one view for each model. This view shows all the records in a data grid and the detail of the selected record in a form view. All associations of the record are represented by a Tab Navigator. You will notice that this is not very practical for the Typo datamodel. We should have main ActiveRecords that are entry points to the application. Also the depth of the active record view is one association down but could be driven by definition i.e. Team => Coach => Sponsor, similar to the :include option of the find methods. We should be able to flatten a “to one” relation and have all the attributes of the association in the same view than the source ActiveRecord.

You can run the application and view the source.

The main application, FlexScaffolding, adds dynamically a ActiveRecordsView for each ActiveRecord in the model to the Tab navigator. That’s too many tabs for the Typo model…

private function generateView():void { for each (var activeRecord:XML in definition.children()) { var arView:ActiveRecordsView = new ActiveRecordsView(); arView.definition = activeRecord; mainView.addChild(arView); } }

The ActiveRecordsView.mxml does the main work of generating the UI. It’s not very big (66 lines), but is also limited for now. I let you check out the source code if you a curious. Next on the list is to map too more data types (ie a “text” ActiveRecord attribute should be mapped to a TextArea, date and datetime should be support). I need to add configuration options where the defaults can be overridden. I need to create a Rails controller that uses the same xml model to expose the data to the view. There shouldn’t be the need to hand code RESTFul controllers. Or maybe the UI should be build from the routes…

That’s all for now. Enjoy!
Daniel Wanja

Fork me on GitHub