Monthly Archive for September, 2008

Ruboss - Overview of Architecture and Magic

Architecture of the Ruboss Application

The Flex Part:

Let’s first take a look at the Flex front end. The main goal of an Enterprise Flex application is to send and receive data to/from a server. Data may be sent in three main formats: XML, JSON, or AMF. XML as a data transfer format is the simplest to understand and most widely used, so that’s what we will use here. JSON is an up and coming format that uses a hash of key:value pairs to transfer data and is thus faster than XML, which can become bulky. AMF is Adobe’s binary data transfer format (Action Message Format) and is by far the fastest to transfer data, but we will save that for later.

So our goal is send XML data from Flex (or Flash, it’s just Actionscript) out to a server so a language such as Ruby, PHP, or Python can act do something with it (access a database, store it on a remote hard drive, etc.); we are using Ruby. Once Ruby does its thing to the data, it sends back data to Flex in any format (and it can be a different format). Flex then displays the changes on the user interface. All of this data transfer occurs RESTfully, that is, occurs over HTTP using only GET, POST, UPDATE, and DELETE.

So what is happening???

Enter Cairngorm. Enter RESTful Cairngorm. When we type text into the Post text input boxes and check the check boxes in the view, and click “Save”, here’s what happens, in a nutshell…

View:
-Text and checkbox data are assigned to the attributes of the Post model. Our Post model has the attributes title, subtitle, body, author, published boolean, and created_at date.
-The button click executes a simple function and passes it a RESTful Event type: sendData(Flexible_blogEvents.CREATE_POST).
-The sendData(eventType) method dispatches a Cairngorm Event (a regular Event with the added data:* parameter that we use to pass in the Post model) of eventType Flexible_blogEvents.CREATE_POST.

Controller:
-A centralized FlexibleBlogEvents class keeps a list of all the RESTful Events in the application. This eliminates the need to have a potentially unlimited number of similar event classes.
-The AppController class is instantiated in the Flexible_blog.mxml main Application MXML file. This allows all events to be listened to and acted upon from the centralized main application file. The AppController executes the appropriate Command based on the Event it receives, and passes the Command the Event along with its data. In our case, the PostCommand would be passed the CairngormEvent of type Flexible_blogEvents.CREATE_POST and executed.
-The PostCommand’s execute() method is called, assigns the event.data value (the Post model and the values it was assigned from the view) to a variable called editedPost of type Post, and calls the corresponding createPost() RESTful method. The createPost() method then does some neat Ruboss magic. Where you would normally have to create a delegate and then do a complicated HTTPService request, Ruboss made it so all you need to do is call the create() method on the editedPost model and pass it a callback function. We do this with the line: editedPost.create({afterCallback: onPostCreate}).
-All of the complicated data transferring over the server to Rails and ultimately to MySQL is handled by some Ruboss magic we don’t have to worry about, but I’ll go a little in a bit anyway.

Model:
-The model extends the RubossModel class, allowing us to call RESTful methods directly from the model. The model is also an Actionscript representation of the database entity, so it has a reference to all of its attributes and its relationships to other entities (belongs_to, has_one, has_many). Our Post model has the attributes title, subtitle, body, author, published, and createdAt.
-I’ve also included a ModelLocator that is instantiated anywhere we want to change the view state of the application (say, from the login screen to the main application).

So now we have a Flex application that follows a RESTful MVC Architecture. Cairngorm was made RESTful by 1) creating a single and centralized Events class that is really just a collection of strings, and 2) creating a single Command for every Model that executes either of four RESTful methods based on the Event type (done by Ruboss magic). Now you hardly have to think about how to connect a Flex UIComponent to a database.

Ruboss’s Flex Magic:

Ruboss effectively eliminates the need to manually use Flex’s HTTPService class to talk to transfer data across a server. It does so through its RubossModelController class. The RubossModelController’s main job is to call the appropriate RESTful methods on a model. So if you send an event type Flexible_blogEvents.CREATE_POST, it will execute the create() method on the Post model in the RubossModelController. each RESTful method has reference to the targetServiceId (HTTP, AMF, etc.), the metadata of the model as it transfers across the server, and a a callback object to handle the server response. All the hard stuff is done for you! Note, only the “index” and “show” methods dispatch a propertyChange event, allowing Flex to update its view.

Another important Ruboss class is the SimpleHTTPController. It has one method called send() that instantiates Flex’s HTTPService, assigns the service an HTTP method, and uses an AsyncToken to send the HTTP request to the server. This is how it is used, for example, in creating a “session” from the SessionsCommand.as file:

public function createSession():void {
     // the "session" is the url we invoke in rails.
	new SimpleHTTPController().send("session", {login: session.login,
	password: session.password}, SimpleHTTPController.POST, this);
     // "this" is the "responder"
}

Because Flex and Actionscript only support two HTTP methods (GET and POST), Ruboss does some magic to add DELETE and UPDATE. Pretty neat! To see an example of how to use the SimpleHTTPController class in a Command, check out how the SessionsCommand was implemented.

Now we have the RubossModel class. This is a bindable class that all models extend (like our Post model) that 1) creates variables for each model attribute you typed into the command line, and 2) allows you to call RESTful methods directly from itself. Again, the “show” method dispatches a propertyChange event to update Flex’s view.

In order to clone a model, use the RubossUtils class: RubossUtils.clone(model). It also has functions to see if the model belongs_to another model, or has_many or has_one of some other model. There’s some great stuff in this class.

Finally, we have the main Ruboss class. The only two things you need to know now about this class are that it has a reference to the ModelsCollection class through the variable “models”, and the “filter()” method. When you call the “create()” method on your Post model (or any other of the RESTful methods), the RubossModel class executes the following:
Ruboss.models.create(editedPost, onPostCreate). Ruboss handles a lot of the repetitive coding was handled for us in the background. You use the filter method if you want to provide different views of the same model. Implement it like this:

Ruboss.filter(Ruboss.models.index(Post), yourFilterFunction);

There is also an AirServiceProvider class, but we will do that sometime later. That’s it for the Ruboss magic! Ruboss takes care of all the HTTPService requests in the background, making it so we can just call the method we want from the model. In addition, the Ruboss Framework is extremely elegant and only consists of 22 classes. Nice.

The Rails Part…

So now we have XML data (or JSON or AMF) that has bend sent from Flex as an HTTP request, and our Rails side of the application needs to handle it. No problem. This works because of Rails “routing” and its MVC architecture.

When we called the editedPost.create() method, an HTTPService request was sent that was packaged with a URL to manipulate our database Post model. It sends off a URL called “posts” along with the method “POST”. The URL “posts” tells you that we are using the posts_controller. When Rails receives this URL request and HTTP method, it executes the “create” method in Ruby.

Here is the “create” method that Ruboss scaffolds for us:

# POST /posts
# POST /posts.xml
# POST /posts.fxml
def create
  @post = Posts.new(params[:post])
 
  respond_to do |format|
    if @post.save
      flash[:notice] = 'Post was successfully created.'
      format.html { redirect_to(@post) }
      format.xml  { render :xml => @post, :status => :created, :location => @post }
      format.fxml  { render :xml => @post }
    else
      format.html { render :action => "new" }
      format.xml  { render :xml => @post.errors, :status => :unprocessable_entity }
      format.fxml  { render :xml => @post.errors }
    end
  end
end

Every Ruby on Rails controller class looks the same, thanks to the excellent design patterns and scaffolding. First we create a new post, then the respond_to do block saves the Post and renders the result as either HTML or XML. I’m guessing the FXML format is “Flex XML” and basically reformats the XML to get rid of dashes and subtle formatting differences between Flex and Ruby on Rails. All of that is happening in the background. To see how it actually works, go to the file in the vendor/Plugins/ruboss_rails_integration/lib directory called ruboss_rails_integration.rb. This is where they register the FXML mimetype and do all the conversions and such.

Here’s what happens in Ruby on Rails in a nutshell…

View
- Ruboss doesn’t use Rails’ ActionView templates because of Flex. So our View is Flex, and it sends its data as XML (or JSON or AMF).

Controller
-URL from the Flex HTTPService request is routed to the appropriate controller (posts_controller in this case) via the routes.rb file.
-The appropriate controller method is executed (”create” in this case). This access and manipulates the database object using, for instance, Post.find(:id) for “show” or Post.new(params[:post]) for “create”.
-The resulting data is returned to the controller and then formatted to XML or any other specified format. This is then read by Flex.

Model
-In its most basic form, the model has just references to the objects it associates with (belongs_to, has_one, has_many). Can have other methods if you want to organize the data a certain way.
-A Migration file is created (create_posts) that allows for easy integration of the model into the database.

That’s it for now.

ToDo’s:

- Create a scale-proof Ruby on Rails server cluster to embed into Ruboss (Heroku?)
- Create Flex MXML templates for a Blog, Comments, Search (with Sphinx) Forum, Profile, Wiki, PhotoGallery, and Podcast Viewer.

Share This Post

If you enjoyed this post, make sure you subscribe to my RSS feed!

Ruboss Tutorial - The Design of Flex on Rails

I love my morning espresso and biscotti! Strada is a Godsend.

This is going to be my first complete tutorial for the Social Computing world on how to use the most cutting edge open source Enterprise Web 2.0 Application Framework ever, Ruboss. Check it out! With a community of active Ruboss contributors, we will, in very short order, take the internet by storm. Building websites like Facebook or Youtube or Digg with an interactive Flash and/or Flex interface will be so insanely simple (Heroku for the backend server scaling) that any one individual could support such a data-driven madhouse. Add to this all of the functionalities of web services available (google maps, amazon, salesforce …), and we have an information revolution.

But in order to get to this point, some key principles must be well understood. These are found within DESIGN PATTERNS, and the principles of REST. With the publication of Design Patterns - Elements of Reusable Object-Oriented Software Fall of 1994, the Gang of Four ushered in a new age of building scalable, reusable, and extremely well-defined software components. J2EE, the Java 2 Enterprise Edition, then implemented and expanded on these core Design Patterns into the famous MVC (Model View Controller) application framework. However, they and no software other group or company has, for one reason or another, been able to unite together and implement a powerful AND well excepted Web Application Framework for building amazing, highly structured, and repeatable software components based on design patterns.

Enter Flex, Cairngorm, and Ruby on Rails.

2004 was a BIG year… Flex packages Actionscript into an XML document, Cairngorm packages Flex XML Documents into an Enterprise application that can efficiently talk to a backend database, and Ruby on Rails comes out and revolutionizes the way people around the globe build software and web applications. Everyone is super excited.

Flex takes Actionscript, the most widely adopted and interactive-friendly programming language to hit the internet and turns it into basically an XML document, so what took 10 lines of code in Actionscript now takes only 1 line in Flex XML (MXML for Macromedia XML). Actionscript and Flash by themselves took over the interactive market. At around the same time, a few Adobe consultants recognized the limitations faced by J2EE developers when building Rich Internet Applications and released Cairngorm for Flex, an Enterprise level
Warning: gzuncompress() [function.gzuncompress]: data error in /home/.zwingli/lancorn411/systemsofseven.com/blog/wp-content/plugins/easyswf.php on line 255
.

David Heinemeier Hansson, creator of Rails, saw the inefficiencies and repetitives tasks required to build web applications and used cutting edge design patterns to automate almost all of these commonalities using the dynamic programming language Ruby.

Now, in 2008, Peter Armstrong and Dima Berastau have integrated Flex and Ruby on Rails into the most powerful, highly efficient, and scalable Rich Web Application Framework, Ruboss. This is it! What all of these frameworks have in common is very well thought out design patterns that allow us to think about building software on the web like scientists, something that most other programming languages are leaving out of the picture and which is hurting them tremendously.

Design Patterns and the Evolution of the Universe

Design Patterns are the best things to have hit the software world in my opinion. They tie software development perfectly into the evolutionary process of the universe. Once they are set into place, you no longer have to think about the implementation details because they follow consistent patterns. This is the basis of evolution: as complexity arises, patterns emerge from these complexities and ultimately become new entities themselves. And as these entities grow in number, they create a new complex system out of which new patterns arise, on and on and on into the infinite…

Energy condenses into atoms; atoms condense into molecules; molecules into cells; cells into organisms; organisms into intelligent organisms. Thoughts become encapsulated into words, which are strung together into sentences and stories, and sent as signals to other human beings for them to unpack and understand and integrate into their own being. Ken Wilber, a prominent philosopher today, has come up with a universal theory of how all things in the universe are modeled, as holons, or whole-parts, and this can be seen in design patterns. With patterns implement at all levels, we can focus on the highest level, which is, ultimately, our own experience in the world–our ideas and our communication of those ideas to other people.

We are now at the point of implementing these evolutionary design patterns into the web to create a foundation of richly interactive and database driven content, freely accessible and modifiable by the social computers, us. I recommend these books and people, in no particular order, to get going on understanding design patterns and their implementation for the evolution of the social web:

And the second important principle is REST, Representational State Transfer. If there is one things that needlessly increases the complexity of a software application, its creating un-RESTful methods when they can be RESTful. In short, all actions between a User Interface and a Database can be mapped onto four simple HTTP methods: GET, POST, UPDATE, and DELETE. These four methods comprise the Universal Interface. Before this design pattern was discovered/revealed, it was often difficult to tell how to do certain things to data in a database. But recognizing that you only need to do these four things, ALL of the thinking is done for you, AND we now have a template by which all Flex UIComponents access a database. Now if you want to make a blog post component for instance, know that it only needs to implement those four methods; same for most everything else.

In order to hasten the evolution of the social interactive web, I recommend getting to know these books well, along with the ones above, as they are the basis of everything in this tutorial:

——- THE RUBOSS TUTORIAL: ——-

Ruboss currently consists of a Flex front end and a Ruby on Rails back end. Ruby on Rails then uses ActiveRecord (Martin Fowler’s design pattern) to access the database, abstracting away all the complicated SQL. I have also modified the Ruboss plugin to include the ability to load files to/from the server from Flex and to create authenticated users. Download it for the tutorial.

To get you started using Ruboss, make sure you have installed Ruby, Rails, Mongrel, Flex 3 (or the Flex 3 SDK), and MySQL. Then download the plugin-enhanced Ruboss. We will first create a single Flex UIComponent, a blog “Post”, and see how everything is wired together. Then we will add to it to create the beginnings of a Flexible Blog, which, in short order, can surely be made into an open source Flexible Social Networking Platform.

Creating a Flex UIComponent with Ruboss…

Let’s start by creating a new project called “flexible_blog” in rails:

cd Documents/rails
rails -d mysql flexible_blog

Next, place the plugin-enhanced Ruboss to the vendor/Plugins directory:

ls
ruboss_rails_integration

Now run the rconfig command to generate Flex and Rails scaffolding for the application (”scaffolds” are just predefined template classes to get you going, taking most of the initial work out of the project):

ruby script/generate rconfig
      create  .flexProperties
      create  .actionScriptProperties
      create  .project
      create  html-template/history
      create  html-template/index.template.html
      create  html-template/AC_OETags.js
      create  html-template/playerProductInstall.swf
      create  html-template/history/history.css
      create  html-template/history/history.js
      create  html-template/history/historyFrame.html
      create  app/flex/flexible_blog/components
      create  app/flex/flexible_blog/controllers
      create  app/flex/flexible_blog/commands
      create  app/flex/flexible_blog/models
      create  app/flex/flexible_blog/components/generated/users
      create  lib/ruboss.swc
      create  public/javascripts/swfobject.js
      create  public/expressInstall.swf
overwrite public/index.html? (enter "h" for help) [Ynaqdh] a
forcing ruboss_config
       force  public/index.html
      create  app/flex/lib
      create  app/flex/lib/Cairngorm.swc
      create  app/flex/com/pomodo/utils
      create  app/flex/com/pomodo/utils/CairngormUtils.as
      create  app/flex/flexible_blog/controllers/AppController.as
      create  app/flex/flexible_blog/models/Flexible_blogModelLocator.as
      create  app/flex/flexible_blog/controllers/Flexible_blogEvents.as
      create  app/flex/skins
      create  app/flex/skins/aqua
      create  app/flex/skins/aqua/fonts
      create  app/flex/skins/aqua/images
      create  app/flex/skins/aqua/CSSPlus.swc
      create  app/flex/skins/aqua/Aqua.css
      create  app/flex/skins/aqua/fonts/lucidaGrande.swf
      ... lots of Aqua png image files ...
  dependency  ruboss_controller
      create    app/flex/flexible_blog/controllers/Flexible_blogController.as
      create  app/flex/flexible_blog/components/generated/users/MainBox.mxml
      create  app/flex/Flexible_blog.mxml

Next, set up your database connection. We are using MySQL.

rake db:mysql:stage ADMINPASS="mysql root password" USER="root"

If you haven’t yet set a root password for MySQL, type the following:

sudo mysqladmin -u root password your_password

Now we will generate a scaffold for a blog “Post” and rerun rconfig to wire up the Flex Application controller and the events with the models, views, and commands. Our blog Post will have a title, a subtitle, a body, an author, a published boolean, and a created_at date. Also, to make it authenticated, we will say that it belongs_to a user, an authenticated User.

ruby script/generate rscaffold post title:string subtitle:string body:text author:string published:boolean created_at:date belongs_to:user with_user:user
      exists  db/migrate
      create  db/migrate/20080903234914_create_posts.rb
      create  app/controllers/posts_controller.rb
      create  app/models/post.rb
      create  test/fixtures/posts.yml
      create  app/flex/flexible_blog/models/Post.as
      create  app/flex/flexible_blog/components/generated/PostBox.mxml
       route  map.resources :posts
      exists  app/flex/flexible_blog/commands
      create  app/flex/flexible_blog/commands/PostCommand.as
  dependency  rcontroller
       force    app/flex/flexible_blog/controllers/Flexible_blogController.as
  dependency  scaffold
      exists    app/models/
      exists    app/controllers/
      exists    app/helpers/
      create    app/views/posts
      exists    app/views/layouts/
      exists    test/functional/
      exists    test/unit/
      exists    public/stylesheets/
      create    app/views/posts/index.html.erb
      create    app/views/posts/show.html.erb
      create    app/views/posts/new.html.erb
      create    app/views/posts/edit.html.erb
      create    app/views/layouts/posts.html.erb
      create    public/stylesheets/scaffold.css
        skip    app/controllers/posts_controller.rb
      create    test/functional/posts_controller_test.rb
      create    app/helpers/posts_helper.rb
       route    map.resources :posts
  dependency    model
      exists      app/models/
      exists      test/unit/
      exists      test/fixtures/
        skip      app/models/post.rb
      create      test/unit/post_test.rb
        skip      test/fixtures/posts.yml
      exists      db/migrate
Another migration is already named create_posts: db/migrate/20080903234914_create_posts.rb

The last line doesn’t matter (I’ll fix that later). The rscaffold command creates for you:

For Ruby on Rails:

  • posts_controller.rb => controller
  • post.rb => model
  • create_posts.rb => migration
  • posts_helper.rb => helper (does nothing now)
  • posts.yml => yaml scaffold
  • map.resources :posts => routing for posts

For Flex:

  • Post.as => model
  • PostBox.mxml => view UIComponent
  • PostCommand.as => command

Ruboss for Ruby on Rails - The Main Parts

The Post Controller:

The posts_controller defines 6 RESTful methods, all based off the four basic HTTP methods: GET, POST, UPDATE, and DELETE:

  • index => retrieves all of the posts (based on user if you specify with_user)
  • show => retrieves a specific Post
  • new => refreshes the page if an error occurs, it is not used by Ruboss
  • create => creates and saves a new Post into the database
  • update => edits the Post if you have modified it
  • destroy => deletes a specific Post from the database

posts_controller.rb

class PostsController < ApplicationController
 
  # GET /posts
  # GET /posts.xml
  # GET /posts.fxml
  def index
    @posts = current_user.posts
 
    respond_to do |format|
      format.html # index.html.erb
      format.xml  { render :xml => @posts }
      format.fxml  { render :xml => @posts }
    end
  end
 
  # GET /posts/1
  # GET /posts/1.xml
  # GET /posts/1.fxml
  def show
    @post = current_user.posts.find(params[:id])
 
    respond_to do |format|
      format.html # show.html.erb
      format.xml  { render :xml => @post }
      format.fxml  { render :xml => @post }
    end
  end
 
  # GET /posts/new
  # GET /posts/new.xml
  def new
    @post = Post.new
 
    respond_to do |format|
      format.html # new.html.erb
      format.xml  { render :xml => @post }
    end
  end
 
  # GET /posts/1/edit
  def edit
    @post = current_user.posts.find(params[:id])
  rescue ActiveRecord::RecordNotFound => e
  	prevent_access(e)
  end
 
  # POST /posts
  # POST /posts.xml
  # POST /posts.fxml
  def create
    @post = current_user.posts.new(params[:post])
 
    respond_to do |format|
      if @post.save
        flash[:notice] = 'Post was successfully created.'
        format.html { redirect_to(@post) }
        format.xml  { render :xml => @post, :status => :created, :location => @post }
        format.fxml  { render :xml => @post }
      else
        format.html { render :action => "new" }
        format.xml  { render :xml => @post.errors, :status => :unprocessable_entity }
        format.fxml  { render :xml => @post.errors }
      end
    end
  end
 
  # PUT /posts/1
  # PUT /posts/1.xml
  # PUT /posts/1.fxml
  def update
    @post = current_user.posts.find(params[:id])
 
    respond_to do |format|
      if @post.update_attributes(params[:post])
        flash[:notice] = 'Post was successfully updated.'
        format.html { redirect_to(@post) }
        format.xml  { head :ok }
        format.fxml  { render :xml => @post }
      else
        format.html { render :action => "edit" }
        format.xml  { render :xml => @post.errors, :status => :unprocessable_entity }
        format.fxml  { render :xml => @post.errors }
      end
    end
  end
 
  # DELETE /posts/1
  # DELETE /posts/1.xml
  # DELETE /posts/1.fxml
  def destroy
    @post = current_user.posts.find(params[:id])
    @post.destroy
 
    respond_to do |format|
      format.html { redirect_to(posts_url) }
      format.xml  { head :ok }
      format.fxml  { render :xml => @post }
    end
  end
end

Each Rails controller is called from Flex’s HTTPService request, and the routes.rb file determines how to route the HTTP request to the appropriate controller. Ruboss added the following to the routes.rb file to make this happen:

map.resources :posts

The appropriate method is then executed in the controller. Then controller the talks to the database using methods on the Post model such as Post.find(:all) or Post.new(), and the result is then formatted into HTML, XML, or FXML (or even JSON or AMF if you’d like!). Flex then receives this data and updates its view! Cake.

Note: I’ve included/created the last argument, with_user, to wire the Ruby posts_controller for restful_authentication, so it can only access the posts that our user is authorized to access. It should be named with the same thing you call your user model (user, person, human, entity, …). if you leave this out, then the controller will retrieve all files regardless of the user. The subtle difference looks like this, for finding all Posts related to one user:

posts_controller.rb with argument with_user:

def index
  @posts = current_user.posts
 
  respond_to do |format|
    format.html # index.html.erb
    format.xml  { render :xml => @posts }
    format.fxml  { render :xml => @posts }
  end
end

posts_controller.rb without argument with_user:

def index
  @posts = Post.find(:all)
 
  respond_to do |format|
    format.html # index.html.erb
    format.xml  { render :xml => @posts }
    format.fxml  { render :xml => @posts }
  end
end

The Post Model:

Ruboss generates a Post model that only has code for its associations, in this case, that it belongs_to the user model:

post.rb

class Post < ActiveRecord::Base
  belongs_to :user
end

The Post Migration:

Ruboss creates this Rails migrations file for our Post automatically:

001_create_posts.rb

class CreatePosts < ActiveRecord::Migration
  def self.up
    create_table :posts do |t|
      t.string :title
      t.string :subtitle
      t.text :body
      t.string :author
      t.boolean :published
      t.date :created_at
 
      # belongs_to the following...
      t.references :user
 
      t.timestamps
    end
  end
 
  def self.down
    drop_table :posts
  end
end

All of the arguments you typed into the command line are mapped here, allowing you to create a posts database table with all of those columns by typing a simple command: rake db:migrate. Migrations are powerful because if you later decide you want to add a number_of_comments column to your posts table, you can easily do that!

Ruboss for Flex - The Main Parts

The Post Model:

Ruboss creates an Actionscript Model class that is essentially a map of the database model found in the create_posts migrations file. It is a Bindable class too, so you can assign any of the variables to values easily in a Flex UIComponent. It also extends the RubossModel class, allowing you to call RESTful methods directly from the Post model. Here’s the class (you don’t need to modify it):

Post.as

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package flexible_blog.models {
  import org.ruboss.models.RubossModel;
 
  [Resource(controller="posts")]
  [Bindable]
  public class Post extends RubossModel {
 
    public static const LABEL:String = "title";
 
    public var title:String;
 
    public var subtitle:String;
 
    public var body:String;
 
    public var author:String;
 
    public var published:Boolean;
 
    public var createdAt:Date;
 
    public var withUser:*;
 
    [BelongsTo]
    public var user:User;
 
    public function Post(
      title:String = "", 
      subtitle:String = "", 
      body:String = "", 
      author:String = "", 
      published:Boolean = false, 
      createdAt:Date = null, 
      withUser:* = null, 
      user:User = null 
    ) {
	   super(LABEL);
       this.title = title;
       this.subtitle = subtitle;
       this.body = body;
       this.author = author;
       this.published = published;
       this.createdAt = createdAt;
       this.withUser = withUser;
       this.user = user;
    }
  }
}

The Post View:

Ruboss generates for you a sample Flex UIComponent to visualize your data! It uses a Datagrid to display all of your database listings, and input boxes to write to the database. Here is the PostBox.mxml file:

PostBox.mxml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
<?xml version="1.0" encoding="utf-8"?>
<mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" label="Post"
  xmlns:rcomponents="org.ruboss.components.*">
<mx:Script><![CDATA[
  import org.ruboss.Ruboss;
  import org.ruboss.utils.RubossUtils;
  import flexible_blog.models.User;
  import flexible_blog.models.Post;