MVC Marathon Part 1: Creating a New Application

| | Comments (5)

Welcome to part 1 of MVC Marathon, a multipart excursion into creating an application in the major MVC frameworks available today.

The source code for this part can be found here: /articles/mvc-marathon/tags/part1-creating-a-new-application/

Part 1: Creating a New Application

The first step in any new application is creating a directory structure and any necessary configuration files. Fortunately, most of the frameworks now a days provide ready made templates or scripts to make getting started as easy as possible.

Today we'll explore how to create and run a new application in the various frameworks and explore the difference between them. You can jump to any specific framework using the links below. For this series of articles, I'm going to assume that you already have the basic frameworks installed.

ASP.NET MVC

Creating the Application

The easiest way to create a new ASP.NET MVC application is using the application templates in Visual Studio. To do that, simply select File -> New -> Project:

aspnetmvc create

In the New Project window, select Visual C# as the language. Select the ASP.NET MVC Web Application, type in the name of the new application, in our case, BurningPlate and click OK. Visual Studio will create a new mvc application looking something like this:

aspnetmvc create

Like nearly all MVC applications, we have the usual Controllers, Models and Views folders along with some other .NET specific folders.

Running the Application

To run your new application, simply hit F5, which will start the application in Visual Studios local web server. This means no messing with IIS until you have to. If all goes well, you should end up with the default home page:

aspnetmvc run

CakePHP

There seems to be at least two ways to create a new CakePHP application. The blog example on the CakePHP website say to just download and extract the latest version and start creating your application in the app subfolder. This seems like a good approach if you're creating app to put on a server where you don't know or control the version or even if CakePHP is installed.

If you're running your own server, you can setup your env to point to a centralized install of CakePHP and use cake to create apps that reference the installed software. We'll do the latter as it closely follows how the other frameworks work.

Creating the Application

First, let's see what cake tells us when we run it:

claco@mbp ~/mvc-marathon $ cake
Welcome to CakePHP v1.2.0.7296 RC2 Console
---------------------------------------------------------------
Current Paths:
 -app: mvc-marathon
 -working: /Users/claco/mvc-marathon
 -root: /Users/claco
 -core: /sw/cakephp/

Changing Paths:
your working path should be the same as your application path
to change your path use the '-app' param.
Example: -app relative/path/to/myapp or -app /absolute/path/to/myapp

Available Shells:

 vendors/shells/:
         - none

 cake/console/libs/:
         acl
         api
         bake
         console
         i18n
         schema
         testsuite

To run a command, type 'cake shell_name [args]'
To get help on a specific command, type 'cake shell_name help'

Next, let's run cake bake help to see what our options are:

claco@mbp ~/mvc-marathon $ cake bake help
Welcome to CakePHP v1.2.0.7296 RC2 Console
---------------------------------------------------------------
App : mvc-marathon
Path: /Users/claco/mvc-marathon
---------------------------------------------------------------
CakePHP Bake:
---------------------------------------------------------------
The Bake script generates controllers, views and models for your application.
If run with no command line arguments, Bake guides the user through the class
creation process. You can customize the generation process by telling Bake
where different parts of your application are using command line arguments.
---------------------------------------------------------------
Usage: cake bake <command> <arg1> <arg2>...
---------------------------------------------------------------
Params:
        -app <path> Absolute/Relative path to your app folder.

Commands:

        bake help
                shows this help message.

        bake all <name>
                bakes complete MVC. optional <name> of a Model

        bake project <path>
                bakes a new app folder in the path supplied
                or in current directory if no path is specified

        bake plugin <name>
                bakes a new plugin folder in the path supplied
                or in current directory if no path is specified.

        bake db_config
                bakes a database.php file in config directory.

        bake model
                bakes a model. run 'bake model help' for more info

        bake view
                bakes views. run 'bake view help' for more info

        bake controller
                bakes a controller. run 'bake controller help' for more info

Since we're starting from scratch, let's give project a whirl:

claco@mbp ~/mvc-marathon/cakephp $ cake bake BurningPlate
Welcome to CakePHP v1.2.0.7296 RC2 Console
---------------------------------------------------------------
App : cakephp
Path: /Users/claco/mvc-marathon/cakephp
---------------------------------------------------------------
Bake Project
Skel Directory: /sw/cakephp/cake/console/libs/templates/skel
Will be copied to: /Users/claco/mvc-marathon/cakephp/BurningPlate
---------------------------------------------------------------
Look okay? (y/n/q) 
[y] >  
Do you want verbose output? (y/n) 
[n] >  
---------------------------------------------------------------
Created: BurningPlate in /Users/claco/mvc-marathon/cakephp/BurningPlate
---------------------------------------------------------------

Creating file /Users/claco/mvc-marathon/cakephp/BurningPlate/views/pages/home.ctp
Wrote /Users/claco/mvc-marathon/cakephp/BurningPlate/views/pages/home.ctp
Welcome page created
Random hash key created for 'Security.salt'
CAKE_CORE_INCLUDE_PATH set to /sw/cakephp in webroot/index.php
CAKE_CORE_INCLUDE_PATH set to /sw/cakephp in webroot/test.php
Remember to check these value after moving to production server
Your database configuration was not found. Take a moment to create one.
---------------------------------------------------------------
Database Configuration:
---------------------------------------------------------------
Name:  
[default] > ^C
		

Running the Application

At first glance, there appears to be no development server for CakePHP applications. There is a script called cakephp-instaweb available on the CakePHP website geared for this purpose. Ironically, the script relies on Python to get the job done. When I ran it, it appeared to work, but all I ever got when trying to hit it with the browser was a CGI SCript Error carping about headers.

The second option is to run this application under Apache. Since I'm on a MacBook Pro and OSX includes a running version of Apache and PHP, all I needed to do was place the BurningPlate directory in my Sites folder. After hitting http://localhost/~claco/BurningPlate/ with my browser we get:

cakephp run

Catalyst

Creating the Application

Just like CakePHP, Catalyst also has a command line utility for creating a new application. Let's see what what it has to say:

claco@mbp ~/mvc-marathon/catalyst $ catalyst.pl
Usage:
    catalyst.pl [options] application-name

    'catalyst.pl' creates a skeleton for a new application, and allows you
    to upgrade the skeleton of your old application.

     Options:
       -force      don't create a .new file where a file to be created exists
       -help       display this help and exit
       -makefile   only update Makefile.PL
       -scripts    only update helper scripts
       -short      use short names, M/V/C instead of Model/View/Controller.

     application-name must be a valid Perl module name and can include "::", 
     which will be converted to '-' in the project name.


     Examples:
        catalyst.pl My::App
        catalyst.pl MyApp

     To upgrade your app to a new version of Catalyst:
        catalyst.pl -force -scripts MyApp

Looks like we just need an application name:

claco@mbp ~/mvc-marathon/catalyst $ catalyst.pl BurningPlate
created "BurningPlate"
created "BurningPlate/script"
created "BurningPlate/lib"
created "BurningPlate/root"
created "BurningPlate/root/static"
created "BurningPlate/root/static/images"
created "BurningPlate/t"
created "BurningPlate/lib/BurningPlate"
created "BurningPlate/lib/BurningPlate/Model"
created "BurningPlate/lib/BurningPlate/View"
created "BurningPlate/lib/BurningPlate/Controller"
created "BurningPlate/burningplate.conf"
created "BurningPlate/lib/BurningPlate.pm"
created "BurningPlate/lib/BurningPlate/Controller/Root.pm"
created "BurningPlate/README"
created "BurningPlate/Changes"
created "BurningPlate/t/01app.t"
created "BurningPlate/t/02pod.t"
created "BurningPlate/t/03podcoverage.t"
created "BurningPlate/root/static/images/catalyst_logo.png"
created "BurningPlate/root/static/images/btn_120x50_built.png"
created "BurningPlate/root/static/images/btn_120x50_built_shadow.png"
created "BurningPlate/root/static/images/btn_120x50_powered.png"
created "BurningPlate/root/static/images/btn_120x50_powered_shadow.png"
created "BurningPlate/root/static/images/btn_88x31_built.png"
created "BurningPlate/root/static/images/btn_88x31_built_shadow.png"
created "BurningPlate/root/static/images/btn_88x31_powered.png"
created "BurningPlate/root/static/images/btn_88x31_powered_shadow.png"
created "BurningPlate/root/favicon.ico"
created "BurningPlate/Makefile.PL"
created "BurningPlate/script/burningplate_cgi.pl"
created "BurningPlate/script/burningplate_fastcgi.pl"
created "BurningPlate/script/burningplate_server.pl"
created "BurningPlate/script/burningplate_test.pl"
created "BurningPlate/script/burningplate_create.pl"

Running the application

Unlike CakePHP, Catalyst includes a development server to get you started. No need to futz with Apache:

claco@mbp ~/mvc-marathon/catalyst $ BurningPlate/script/burningplate_server.pl
[debug] Debug messages enabled
[debug] Statistics enabled
[debug] Loaded plugins:
.----------------------------------------------------------------------------.
| Catalyst::Plugin::ConfigLoader  0.20                                       |
| Catalyst::Plugin::Static::Simple  0.20                                     |
'----------------------------------------------------------------------------'

[debug] Loaded dispatcher "Catalyst::Dispatcher"
[debug] Loaded engine "Catalyst::Engine::HTTP"
[debug] Found home "/Users/claco/mvc-marathon/catalyst/BurningPlate"
[debug] Loaded Config "/Users/claco/mvc-marathon/catalyst/BurningPlate/burningplate.conf"
[debug] Loaded components:
.-----------------------------------------------------------------+----------.
| Class                                                           | Type     |
+-----------------------------------------------------------------+----------+
| BurningPlate::Controller::Root                                  | instance |
'-----------------------------------------------------------------+----------'

[debug] Loaded Private actions:
.----------------------+--------------------------------------+--------------.
| Private              | Class                                | Method       |
+----------------------+--------------------------------------+--------------+
| /default             | BurningPlate::Controller::Root       | default      |
| /end                 | BurningPlate::Controller::Root       | end          |
| /index               | BurningPlate::Controller::Root       | index        |
'----------------------+--------------------------------------+--------------'

[debug] Loaded Path actions:
.-------------------------------------+--------------------------------------.
| Path                                | Private                              |
+-------------------------------------+--------------------------------------+
| /                                   | /default                             |
| /                                   | /index                               |
'-------------------------------------+--------------------------------------'

[info] BurningPlate powered by Catalyst 5.7014
You can connect to your server at http://localhost:3000
[info] *** Request 1 (0.125/s) [1941] [Sat Jun 28 19:24:35 2008] ***
[debug] "GET" request for "/" from "127.0.0.1"
[info] Request took 0.017728s (56.408/s)
.----------------------------------------------------------------+-----------.
| Action                                                         | Time      |
+----------------------------------------------------------------+-----------+
| /index                                                         | 0.000507s |
| /end                                                           | 0.000745s |
'----------------------------------------------------------------+-----------'

The development server was nice enough to tell us where to go. Hitting http://localhost:3000 in our browser yields:

catalyst run

Django

Creating the application

Rinse. Lather. Repeat. As with the previous two frameworks, we just need to run a command line script to create a new application.

claco@mbp ~/mvc-marathon/django $ django-admin.py
Usage: django-admin.py action [options]
actions:
 adminindex [appname ...]
   Prints the admin-index template snippet for the given app name(s).

 createcachetable [tablename]
   Creates the table needed to use the SQL cache backend

 dbshell 
   Runs the command-line client for the current DATABASE_ENGINE.

 diffsettings 
   Displays differences between the current settings.py and Django's
   default settings. Settings that don't appear in the defaults are
   followed by "###".

 dumpdata [--format][appname ...]
   Output the contents of the database as a fixture of the given
   format

 flush [--verbosity] [--interactive]
   Executes ``sqlflush`` on the current database.

 inspectdb 
   Introspects the database tables in the given database and outputs
   a Django model module.

 loaddata [--verbosity] fixture, fixture, ...
   Installs the named fixture(s) in the database

 reset [--interactive][appname ...]
   Executes ``sqlreset`` for the given app(s) in the current
   database.

 runfcgi [various KEY=val options, use `runfcgi help` for help]
   Runs this project as a FastCGI application. Requires flup.

 runserver [--noreload] [--adminmedia=ADMIN_MEDIA_PATH] [optional port number, or ipaddr:port]
   Starts a lightweight Web server for development.

 shell [--plain]
   Runs a Python interactive interpreter. Tries to use IPython, if
   it's available.

 sql [appname ...]
   Prints the CREATE TABLE SQL statements for the given app name(s).

 sqlall [appname ...]
   Prints the CREATE TABLE, initial-data and CREATE INDEX SQL
   statements for the given model module name(s).

 sqlclear [appname ...]
   Prints the DROP TABLE SQL statements for the given app name(s).

 sqlcustom [appname ...]
   Prints the custom table modifying SQL statements for the given app
   name(s).

 sqlflush 
   Returns a list of the SQL statements required to return all tables
   in the database to the state they were in just after they were
   installed.

 sqlindexes [appname ...]
   Prints the CREATE INDEX SQL statements for the given model module
   name(s).

 sqlinitialdata 
   RENAMED: see 'sqlcustom'

 sqlreset [appname ...]
   Prints the DROP TABLE SQL, then the CREATE TABLE SQL, for the
   given app name(s).

 sqlsequencereset [appname ...]
   Prints the SQL statements for resetting PostgreSQL sequences for
   the given app name(s).

 startapp [appname]
   Creates a Django app directory structure for the given app name in
   the current directory.

 startproject [projectname]
   Creates a Django project directory structure for the given project
   name in the current directory.

 syncdb [--verbosity] [--interactive]
   Create the database tables for all apps in INSTALLED_APPS whose
   tables haven't already been created.

 test [--verbosity] [appname ...]
   Runs the test suite for the specified applications, or the entire
   site if no apps are specified

 validate 
   Validates all installed models.

Options:
 --version             show program's version number and exit
 -h, --help            show this help message and exit
 --settings=SETTINGS   Python path to settings module, e.g.
                       "myproject.settings.main". If this isn't provided, the
                       DJANGO_SETTINGS_MODULE environment variable will be
                       used.
 --pythonpath=PYTHONPATH
                       Lets you manually add a directory the Python path,
                       e.g. "/home/djangoprojects/myproject".
 --plain               Tells Django to use plain Python, not IPython, for
                       "shell" command.
 --noinput             Tells Django to NOT prompt the user for input of any
                       kind.
 --noreload            Tells Django to NOT use the auto-reloader when running
                       the development server.
 --format=FORMAT       Specifies the output serialization format for fixtures
 --indent=INDENT       Specifies the indent level to use when pretty-printing
                       output
 --verbosity=VERBOSITY
                       Verbosity level; 0=minimal output, 1=normal output,
                       2=all output
 --adminmedia=ADMIN_MEDIA_PATH
                       Specifies the directory from which to serve admin
                       media for runserver.
	

To create a new app, we'll run the startproject command:

claco@mbp ~/mvc-marathon/django $ django-admin.py startproject BurningPlate

Unfortunately, no matter what --verbosity level I set, this is the only output I get.

Running the Application

claco@mbp ~/mvc-marathon/django $ python BurningPlate/manage.py runserver
Validating models...
0 errors found.

Django version 0.96.2, using settings 'BurningPlate.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
[28/Jun/2008 18:40:25] "GET / HTTP/1.1" 404 2065
	

Lets hit http://127.0.0.1:8000/ and see what we have:

django run

Ruby on Rails

Creating the Application

Another framework; another script.

claco@mbp ~/mvc-marathon/rails $ rails
Usage: /sw/bin/rails /path/to/your/app [options]

Options:
    -r, --ruby=path                  Path to the Ruby binary of your choice (otherwise scripts use env, dispatchers current path).
                                     Default: /sw/bin/ruby1.8
    -d, --database=name              Preconfigure for selected database (options: mysql/oracle/postgresql/sqlite2/sqlite3).
                                     Default: mysql
    -f, --freeze                     Freeze Rails in vendor/rails from the gems generating the skeleton
                                     Default: false

Rails Info:
    -v, --version                    Show the Rails version number and quit.
    -h, --help                       Show this help message and quit.

General Options:
    -p, --pretend                    Run but do not make any changes.
        --force                      Overwrite files that already exist.
    -s, --skip                       Skip files that already exist.
    -q, --quiet                      Suppress normal output.
    -t, --backtrace                  Debugging: show backtrace on errors.
    -c, --svn                        Modify files with subversion. (Note: svn must be in path)

Description:
    The 'rails' command creates a new Rails application with a default
    directory structure and configuration at the path you specify.

Example:
    rails ~/Code/Ruby/weblog

    This generates a skeletal Rails installation in ~/Code/Ruby/weblog.
    See the README in the newly created application to get going.
	

Looks like Catalyst. Give it an app name and go:

claco@mbp ~/mvc-marathon/rails $ rails BurningPlate
create  
create  app/controllers
create  app/helpers
create  app/models
create  app/views/layouts
create  config/environments
create  config/initializers
create  db
create  doc
create  lib
create  lib/tasks
create  log
create  public/images
create  public/javascripts
create  public/stylesheets
create  script/performance
create  script/process
create  test/fixtures
create  test/functional
create  test/integration
create  test/mocks/development
create  test/mocks/test
create  test/unit
create  vendor
create  vendor/plugins
create  tmp/sessions
create  tmp/sockets
create  tmp/cache
create  tmp/pids
create  Rakefile
create  README
create  app/controllers/application.rb
create  app/helpers/application_helper.rb
create  test/test_helper.rb
create  config/database.yml
create  config/routes.rb
create  public/.htaccess
create  config/initializers/inflections.rb
create  config/initializers/mime_types.rb
create  config/boot.rb
create  config/environment.rb
create  config/environments/production.rb
create  config/environments/development.rb
create  config/environments/test.rb
create  script/about
create  script/console
create  script/destroy
create  script/generate
create  script/performance/benchmarker
create  script/performance/profiler
create  script/performance/request
create  script/process/reaper
create  script/process/spawner
create  script/process/inspector
create  script/runner
create  script/server
create  script/plugin
create  public/dispatch.rb
create  public/dispatch.cgi
create  public/dispatch.fcgi
create  public/404.html
create  public/422.html
create  public/500.html
create  public/index.html
create  public/favicon.ico
create  public/robots.txt
create  public/images/rails.png
create  public/javascripts/prototype.js
create  public/javascripts/effects.js
create  public/javascripts/dragdrop.js
create  public/javascripts/controls.js
create  public/javascripts/application.js
create  doc/README_FOR_APP
create  log/server.log
create  log/production.log
create  log/development.log
create  log/test.log
	

Running the Application

claco@mbp ~/mvc-marathon/rails $ BurningPlate/script/server
=> Booting WEBrick...
=> Rails application started on http://0.0.0.0:3000
=> Ctrl-C to shutdown server; call with --help for options
[2008-06-28 19:20:36] INFO  WEBrick 1.3.1
[2008-06-28 19:20:36] INFO  ruby 1.8.6 (2008-03-03) [i686-darwin]
[2008-06-28 19:20:36] INFO  WEBrick::HTTPServer#start: pid=1929 port=3000
127.0.0.1 - - [28/Jun/2008:19:20:41 EDT] "GET / HTTP/1.1" 200 7557
- -> /
127.0.0.1 - - [28/Jun/2008:19:20:41 EDT] "GET /javascripts/prototype.js HTTP/1.1" 200 125605
http://localhost:3000/ -> /javascripts/prototype.js
127.0.0.1 - - [28/Jun/2008:19:20:41 EDT] "GET /javascripts/effects.js HTTP/1.1" 200 38916
http://localhost:3000/ -> /javascripts/effects.js
127.0.0.1 - - [28/Jun/2008:19:20:41 EDT] "GET /images/rails.png HTTP/1.1" 200 1787
http://localhost:3000/ -> /images/rails.png
	

Loading http://0.0.0.0:3000 in our browser, we see:

rails run

Conclusions

There weren't too many shockers here. For the most part, it's just a matter of running a command to get an application structure up and running. There are some areas that could use a few tweaks to help out the people new to their respective frameworks:

  • CakePHP really could use a development server. For development, it's nice to not have to mess with Apache configs.
  • Django needs to output something when it's successfully created a new application. No output equates to thinking nothing happened or that something is broken.
  • Catalyst, Django and Rails would be a touch better if after they created the new applications would tell the user how to run them. i.e. "App created. please run xxx xxxx/xxxxx ro start your new app".
  • All of the frameworks except for ASP.NET MVC tell the user where to go next and/or what files to start to configure. It would be nice if ASP.NET MVC did the ame thing rather than just display the "Home" page.

5 Comments

Nah, django is the only one that gets it right. The Unix philosophy is "no output means success". The others are all achieving Java-like levels of verbosity. :-)

Good initiative, I'm looking forward to the rest of this series.

> The others are all achieving Java-like levels of verbosity. :-)

haha i can vouch for that! java's logging (especially spring, hibernate etc) are getting quite ridiculous....

Is there any reason you are using Django .96? All the documentation suggests that you use their SVN version (don't worry, quite stable) rather than using their soon-to-be replaced .9X series.

Re: 0.96

Because that's what fink curreny has and I didn't want to spend any more time than necessary installing and upgrading to non-release versions.

The only reason I'm using CakePHP 1.2 non-release that it's 0-install.

Leave a comment

About this Entry

This page contains a single entry by Christopher H. Laco published on June 29, 2008 9:24 PM.

MVC Marathon was the previous entry in this blog.

MVC Marathon Part 2: Creating a Database and Model is the next entry in this blog.

Find recent content on the main index or look in the archives to find all content.