Mvc Dev In Ruby
Ruby is dynamic object-orientated language that has a simple and elegant syntax enabling users to write beautiful code. Cocoa is Apple’s object-orientated Model View Controller (MVC) framework for building applications for MAC OS X. Cocoa is implemented in Objective-C, an object-orientated language that is compiled at run time like Ruby.
RubyCocoa is a bridge between the Ruby language and the Objective-C needed by Cocoa. It provides a way to write beautifully coded and beautiful looking Mac OS X applications with the same behaviors and appearances as native Mac applications.
Introduction
The Ruby language has seen a resurgence in its popularity over the last few years because of popular web frameworks like Ruby On Rails (RoR) and Merb. Having a background in RoR, RubyCocoa provides a straightforward way of transitioning to Mac OS X development. Cocoa is a Model, View and Controller framework not unlike Ruby on Rails. I will explain the concept of Model-View-Controller architecture, talk about why the Ruby On Rails framework is so popular and show how to use the same architecture concepts to create beautiful MAC OSX applications with Ruby Cocoa.
I will also give a basic introduction on how to use the Cocoa framework with Ruby Cocoa using XCode and Interface Builder. The application that is referred to in this paper is called MovieStore and was the project for COMP 120 Databases course at Tufts. The code is hosted at http://github.com/wmernagh/MovieStore.
Model View Controller
The purpose of the MVC framework is to separate concerns in order to make development and maintenance less challenging. It separates the business logic and data from the presentation of data in the user interface.
The Model is the representation of the applications data. All persistent data becomes part of the model. The model also provides an interface to access the data and handles the retrieval and persistence of the data (the business logic of the application). The model is unaware of how the data will be displayed in the User Interface (UI). It just provides ways to access, and modify it. In most applications all classes of data will provide basic CRUD (Create, Retrieve, Update, Destroy) operations.
The View is the presentation logic of the application. The view retrieves data from the model and renders it in the UI. It also provides a UI for modifying data and sends modified data back to the Model. It is not concerned with checking the validity of the data just with presenting it to the user. Nor is the view concerned with any other business logic. If the business logic changes in the model it will not affect the view which just presents whatever data it can retrieve. There can be multiple views for a single model, each one presenting the data in a different ways (i.e. a photo application may present an album as a list of thumbs, a slide show, etc.)
The Controller provides the connection between the model and the view. All application requests are sent through the controller. The controller retrieves the correct data from the model based on the view to be rendered. It will also determine which view to display based on the action requested and the requester.
Ruby on Rails
Ruby on Rails has become a very popular web development framework. It is a MVC framework that preaches the philosophy of “Convention over Configuration” CoC and the principle of “Don’t Repeat Yourself” DRY. The CoC means that a developer only needs to specify non-conventional parts of their application. For example, an application with a Movie model will have a table called Movies in the database. If the table was called videos then the developer would have to specify that but the convention expects movies (pluralization of the Model name). It encourages the MVC framework by providing the developer with the skeleton of an MVC application and a scaffolding mechanism. The scaffold will generate the Model, Controller and CRUD views needed. All that developer is required to do is specify the attributes of the model.
$ ruby ./script/generate scaffold Actor first_name:string \
last_name:string dob:date
exists app/models/
exists app/controllers/
exists app/helpers/
create app/views/actors
exists app/views/layouts/
exists test/functional/
exists test/unit/
exists test/unit/helpers/
exists public/stylesheets/
create app/views/actors/index.html.erb
create app/views/actors/show.html.erb
create app/views/actors/new.html.erb
create app/views/actors/edit.html.erb
create app/views/layouts/actors.html.erb
identical public/stylesheets/scaffold.css
create app/controllers/actors_controller.rb
create test/functional/actors_controller_test.rb
create app/helpers/actors_helper.rb
create test/unit/helpers/actors_helper_test.rb
route map.resources :actors
dependency model
exists app/models/
exists test/unit/
exists test/fixtures/
create app/models/actor.rb
create test/unit/actor_test.rb
create test/fixtures/actors.yml
exists db/migrate
create db/migrate/20100411200441_create_actors.rb
Once the scaffolding is in place for all models the developer can add the business logic to each model (validations and associations). That then just leaves UI design and some tweaking. Rails also offers conventions for implementing the necessary validations and associations.
Associations
Connecting models together logically. e.g. A movie can have many actors and an actor can be in many movies. So there is an obvious many-to-many relationship. The convention in Rails would be to have three tables representing the models movies and actors, as well as a table to associate them together called actors_movies. Then two classes called Movie and Actor are updated as follows in order to make the association.
class Movie < ActiveRecord::Base
has_and_belongs_to_many :actors
end
class Actor < ActiveRecord::Base
has_and_belongs_to_many :movies
end
The attributes of a model are determined by doing an SQL show command on the DB. This is done behind the scenes and the developer need not be concerned with it. The schema from the scaffold command above will look like the following.
movies actors actors_movies
================================
id id actor_id
title first_name movie_id
year last_name
genre dob
Now the code to access attributes of the models and their associations is nice and simple.
a_movie = Movie.new
a_movie.title = 'Avatar'
a_movie.year = '2009'
a_movie.save
an_actor = Actor.new
an_actor.first_name = 'Peter'
an_actor.last_name = 'Smith'
an_actor.save
a_movie.actors #=> []
a_movie.actors << an_actor
a_movie.actors #=> [<Actor first_name => 'Peter'...>]
a_movie.actors.first == an_actor #=> true
an_actor.movies.first == a_movie #=> true
Validations
Validations are used to ensure that all data is present and in the correct format prior to persisting it. Rails provides the developer with tools to easily validate their models prior to persisting them. This, a long with the association tools sown above, abstracts the persistence layer out of the code (For the most part - for performance the developer will need to have some knowledge of the underlying DB. Although with the upcoming Rails 3 and Arel that will change for the better by ).
Updating the model code above to apply some validation
class Actor < ActiveRecord::Base
has_and_belongs_to_many :movies
validates_presence_of :first_name, :last_name, :dob
validates_uniqueness_of :first_name, :scope => :last_name
end
class Movie < ActiveRecord::Base
has_and_belongs_to_many :actors
validates_presence_of :title, :year
validates_uniqueness_of :title, :scope => :year
end
Validations are run whenever a persistence method is called (create, create!, update, update!, save, save!, etc.). For each persistence method there are two forms (e.g. create and create!). The methods followed by an ! will throw an Exception if the validation fails and rollback the current transaction. The methods without the ! will return true if valid, or false if invalid and rollback the current transaction.
All ActiveRecord inherited models have a reference to their ActiveRecord::Errors object. This object gets updated with the validation errors that resulted form calling the above methods. This can then be used to inform the user as to what the reason for the failed method call was. Each validation has a specific error message which can be overwritten either in the declaration of the validation (not recommended) or in a localization file.
Embedded Ruby (.erb)
The views in Rails can contain embedded ruby code similar to PHP and ASP. The code is surrounded by <% %> or <%= %>. The former is used for code that does not return text and the latter is used for writing text to the page.
Here is a simple example of how to print the actors in a movie. (taken from the show.html.erb file)
<ul>
<% @movie.actors.each do |actor| %>
<li><%= actor.last_name %>, <%= actor.first_name %></li>
<% end %>
</ul>
Actions
Rails is a RESTful web application framework providing actions to be requested by users (via a browser for example). An action is a controller method that can be executed by a user via some widget in the view or by an API call.
Execution of an action in a Rails application is called by a request to the the url path with one of the following HTTP methods (POST, GET, DELETE, PUT). For the action to be called the view needs to provide a submit button, a link, or some JavaScript callback to send a request to a path on the server.
In rails the convention for controllers is to have the following actions (you can add more by creating a public method and updating the routes.yml file)
Controller Route
Action Method Path Example Path HTTP Method
========================================================================
index index :controller/ /movies/ GET
show show :controller/:id /movies/2192 GET
new new :controller/new /movies/new GET
create create :controller/ /movies/ POST
edie edit :controller/:id/edit /movies/2192/edit GET
update update :controller/:id /movies/2192 PUT
delete destroy :controller/:id /movies/2192 DELETE
In the running example if we wanted to see the details of the movie “Avatar’ we would enter the path ‘/movies/2192’ into our browser (the full url would look something like http://www.example.com/movies/2192) where ‘Avatar’ has the id 2192 in the database.
If the above path is called with a GET request it will then be routed to the controller MoviesController and to the show action. Again this is because of convention.
def show
@movie = Movie.find(params[:id])
respond_to do |format|
format.html #=> By default this will render show.html.erb
format.xml { render :xml => @movie }
end
end
The show action is used to render a particular view and to populate the variables needed by that view. The convention would render a view of the same name as the action. So show.html.erb in this example.
If the above path is called with a PUT request it will then be routed to the movies controller and to the update action.
def update
@movie = Movie.find(params[:id])
respond_to do |format|
if @movie.update_attributes(params[:movie])
flash[:notice] = 'Movie was successfully updated.'
format.html { redirect_to(@movie) }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => @movie.errors,
:status => :unprocessable_entity }
end
end
end
The path ‘/movies/2192.xml’ would map to the same actions but would return the movie model as xml.
Not all methods in a controller are actions. To be considered an action a controller method must be public and there must be a path defined in the routes.yml file that maps to it. It is good practice to have all non action methods be private or protected.
The controller passes data between Model and View in two ways. When a action is requested it connects data set in the View with the Model by reading parameters in the session (these get added to the params hash). It then connects data in the Model for use by the View by setting instance variables.
Skinny Controllers and Fat Models
Another principle that is popular in the Rails community is Skinny Controllers and Fat Models. This refers to the idea that most of the logic should be in the Models, cleaning up the Controller code allowing for grater code reuse. This principle is valid for all MVC applications not just the Rails framework. New developers tend to start with logic in the View, then move it to the controllers and finally as they get familiar with the benefits of the MVC framework they move it down to the Model.
The Cocoa Framework
The Cocoa Framework also encourages the MVC pattern. It includes a graphical view builder called Interface Builder which can be used to create the View of the application. This can be done without any code allowing you to focus directly on the User Interface. The framework also provides a mechanism called bindings to connect your View to the controllers coded in Objective-C or Ruby. This is also a simple graphical step of dragging a “wire” from the one controller action to an object/widget in the view.
To create a new project open XCode -> New Project

Select Cocoa-Ruby Application and click ‘Choose…’ name the project ‘Movies’ and the following window will open.

The View
As mentioned above the View can be created using the a graphical tool called Interface Builder. To open Interface Builder simply double click on the .nib file that is in XCode (It is named MainMenu.nib by default but can be renamed if wanted).

Interface Builder will open with 5 windows (show above). The AppKit Library (left), Document Window (top center), Inspector (right), The applications menu (center), and the applications window (bottom center).
The AppKit is a library of all the application widgets you will need (windows, panels, text boxes, tables, buttons, etc.). These objects can be dragged from the library into the application window.

The figure below shows how you would drag a button widget from the library to a window, place it beside a password text field and edit it to say ‘Login’.

In order to create your applications View you can add the needed widgets, position and edit them (size, style, etc.). The AppKit will have all the widgets that you could need including nice table widgets that handle sorting, in-line cell editing, etc.
The one major downside to Interface Builder is that if you layer objects on top of each other it makes modifying the underlying objects difficult. You actually have to remove the object from the View that are on top of the object you would like to edit.
The Controller
The controller will be used to marshal the view, retrieve data from the model layer for the view, and to pass data from the view to the model layer. This adheres to the MVC architecture described earlier. To create a controller select File -> New File in Xcode, then click on the Ruby NSObject subclass option and click Next and name your controller (e.g. ApplicationController)

This will generate the following code
require 'osx/cocoa'
class ApplicationController < OSX::NSObject
end
Like Rails, Cocoa controllers will need to define actions. Unlike Rails where actions were defined by pubic methods in the Controller and a matching route in the routes.yml file, Cocoa controller actions are defined explicitly within the controller. This difference is due to the difference in the application space. Rails is a Web framework so needs to define actions accessible via a route, while Cocoa is a Desktop framework which does not.
To define the actions you will need a public method with an extra definition above it. In the running example we need a login action, it can be defined as follows.
require 'osx/cocoa'
class ApplicationController < OSX::NSObject
ib_action :login
def login
# Do login here
end
end
The extra definition is called ib_action which stands for Interface Builder action. This one line will make the action visible in Interface Builder.
The next step is to connect the the login button in the view to the login action in the controller. In Rails this would be done by having the button either call a JS function, a link, or form submit button, that requests the correct path with the correct HTTP method. In Cocoa we use graphical wiring (called bindings) in Interface Builder.

Going back to Interface Builder select the Classes tab from the Library Window, type in the name of the controller you just created and drag that controller into the Document Window.
Once the controller is in the Document Window you can select it and access its actions in the Inspector. Click and hold the mouse button on the circle beside an action you then drag it to a widget in the View. In the example below we will wire up the Controller’s login action with the View’s login button.

The login button should flash showing you the connection worked and you can see the connection in the Inspector afterward.

You can connect multiple widgets to an action. So we may also want the user to login by hitting the enter key after typing the password. To do this we wire the text field to the login action also.

Now that the actions are connected to the view there is still one more connection that needs to be made. In order for the controllers to pass data between View and Model there needs to be a set of variables associated with the view that can be accessed by the controller.
In Rails this was done in two ways depending on the flow of the data (the params hash gets set for sending data from the View to the Controller and instance variables are set for sending data from the Controller to the View.)
In Cocoa we create outlets in the controller that we can connect to widgets in the view. In our running example we will need a connect the Employee ID and the Password text fields to the ApplicationController so that the login Action can check their values.
Outlets are added in the controller similar to actions and they can be accessed in the controller as instance variables.
require ‘osx/cocoa’
class ApplicationController < OSX::NSObject
ib_outlets :login_username, :login_password
ib_action :login
def login
employee = Employee.find_by_id(@login_username.stringValue_)
# Do login here
end
end
Also note that there are some peculiarities when bridging form Objective-C to Ruby, for example to retrieve the string value of the outlet we use the stringValue method. Similarly when we want to set the value of a outlet we use the setStringValue method. Ruby developers may have expected that the @login_username would be cast to string by default but this is not the case.
Now we need to wire the outlets to the View using Interface Builder. This is done in the same way that we bound the actions to the view.

The difference between Rails and Cocoa in how they share data is somewhat due to the differences between Web and Desktop applications as well as having to integrate with Interface Builder.
The Model
The model layer in Ruby Cocoa can be also take advantage of Rails. Rails uses the ActiveRecord Gem for its model layer. Ruby Cocoa developers can include this gem and use ActiveRecord also. This will provide all the validation, error, and association tools that were mentioned in the Rails section above.
Cocoa API
When using the Cocoa API with Ruby most of the functions that are available in Objective-C are also available in Ruby. The naming convention is to call the same method in Ruby with a trailing underscore. Some examples are
deselectAll_ setHidden_ reloadData_ setStringValue_ stringValue_ tableView_objectValueForTableColumn_row_(view, col, row) tableViewSelectionDidChange_(notification) numberOfRowsInTableView_(view)
Conclusion
MVC
Both Rails and Cocoa provide a developer with good tools to begin programming maintainable applications by separating concerns. The developer is still required to adhere to the principle of Skinny Controllers and Fat Models to ensure the correct levels of modularization. Logic that slips into the Controller or View will be hard to locate and thus maintain. It will also lead to possible code duplication. By moving the logic down to the Model the code becomes more DRY.
Mac OS X Development
Ruby comes installed on all new Macs so developing applications in RubyCocoa should ensure that your application will work on them. Developers who utilize Ruby gems will need to package the gems with the code since it is unlikely that potential users will have the correct gems installed.
RubyCocoa was an open source project started separately from Apple. Apple has since started work on a similar project called MacRuby and HotCocoa. MacRuby is version of Ruby 1.9 ported to run directly on top of core technologies such as Objective-C. HotCocoa is a thin & idiomatic Ruby layer that sits above Cocoa and other frameworks. MacRuby 0.5 now supports HotCocoa.
HotCocoa used to be developed inside the MacRuby project, it has since been moved to GitHub, where it is far easier for developers to submit contributions.
Developers can sign up to the developer connection at Apple for free and download the Cocoa SDK (XCode, Interface Builder, etc.) Rails is also installed on Mac OS X when you install the developer add-ons.
Objective-C the next step
It can often be hard for developers to start work in new environments and with new languages. For developers switching to Mac development and using Objective-C for the first time the learning curve is even steeper. Not only is there a new set of tools (Xcode, Interface Builder, etc.) to become familiar with but also a new language.
However for Ruby developers especially those familiar with Rails there is a nice interim step that can be taken. Developers can create an application with RubyCocoa, learning the framework and the tools used. Then once proficient with these new technologies they can easily transition to building applications with Objective-C.
iPhone Development
Unfortunately the iPhone cannot take advantage of RubyCocoa since the iPhone OS does not have Ruby installed. Perhaps when MacRuby comes out of beta we will see it but until then Objective-C is required to develop applications on the iPhone.
Bibliography Programming Cocoa with Ruby – Brian Marick – prag prog – 2009
blog comments powered by Disqus