September 30, 2009

I’m tired of Custom CMS systems!

In the past few years I’ve build dozens of custom CMS systems. Nearly all of them were written in Rails. And now they are more of a problem than a solution. They all do things in a slightly different way. and there is a lot of duplication across these applications. Not because of the lack of plugins but because all these plugins require you to write or even generate code yourself. The reason why most plugins are written this way is obvious but I still need to do too much.

I hate prefab CMS systems!

I’ve looked at many prefab CMS systems, trying to find a simple solution that would do all the things I needed to do and more importantly all the things our clients needed to do. Another problem with prefab CMS systems is customizability. Some systems like Radiant are fairly customizable but simply too hard for our clients. Others, like Browse CMS, look nice but fail when compared to our wish list.

What I needed.

I wanted a system that was extremely modular, highly customizable and very client friendly. Unfortunately I didn’t find it so I build it myself. Currently most of it is still under wraps but most of the modules/gems/plugins (whatever you would like to call them) will be released under one or an other OSS license. Starting with the core today.

What I made.

The core is called Milkshake and it builds composite Rails applications.
Composite Rails applications are Rails applications that are build using many smaller Rails applications which in there turn can be build using many even smaller Rails applications.

A composite Rails application.
Each node represents a fully functional rails application (except for Paperclip, Globalize, MetaController and MetaERB)

Essentially Milkshake automatically loads gem-plugins, manages migrations and links static assets. This allows any regular gem plugin to become as privileged as any standard Rails application. Milkshake also allows you to take any regular Rails application and build a gem from it.

A list of what Milkshake does.

  • Automatically configure/load dependencies defined in config/milkshake.yml.
  • Automatically migrate the database on relink.
  • Make database snapshots before migrating.
  • Load locale files from gems in rails > 2.3.4.
  • Initializers for gems like config/initializers but in rails/initializers.
  • Symlink public directory from gems into public/vendor/[GEM_NAME].
  • Extract data and configuration directories and files from the rails directory.

Installing Milkshake.

Installing Milkshake is easy but make sure you installed gemcutter.

# only if you don't already have gemcutter installed.
$ sudo gem install gemcutter
$ sudo gem tumble
# now install milkshake
$ sudo gem install milkshake

Building a gem with Milkshake.

# generate an empty gem app
$ milkshake create.gem my_gem
# answer the questions
$ cd my_gem
$ ls
README    app     db    lib   public  script  tmp
Rakefile  config  doc   log   rails   test    vendor

Now you have a regular rails application with some extra files and directories needed for packaging everything up in a gem.

This is the regular Rails gem plugin init file.
In here you can put initializers like in the config/initializers directory. Note that the config/initializers directory doesn’t get packaged.
In this file you define your gem dependencies. This replaces the config.gem directive in the config/environment.rb file.
This file loads the milkshake code and extends Rails.
This rake file contains the Jeweler tasks for packaging the Rails app.

If you look a little deeper you’ll notice that the application_controller.rb and the application_helper.rb are missing. Generally you only add these to the top level gem but you don’t have to as Milkshake has a fallback application_controller.rb which get loaded if you don’t include your own.

After writing some code, adding some migrations and some static assets you can build this rails app like so:

$ rake version:write # only the first time
$ rake gemspec build

A new directory called pkg gets created, it contains the build gems. To install you new gem just do a gem install [pathtogem] or:

$ rake install

Using a Milkshake gem.

# generate an empty host app
$ milkshake my_host
$ cd my_host
$ ls
config  db  log public  script  tmp

As you can see a host app is mush slimmer than a gem app. The reason for this is that you don’t use host apps for development and they should not contain code. They are just used for serving your composite app. Edit the config/milkshake.yml file.

  my_gem: {} # no special lib, no specific version requirement, no specific source

Next touch the tmp/relink.txt file to make sure Milkshake links all the gems into the host app. Note that you need to restart the host app in order to actually run linker. Also note that (re-)linking the host app automatically runs all the migrations.

$ touch tmp/relink.txt
$ touch tmp/restart.txt # restart the web server (in this case passenger)

The way Milkshake alters the Rails initializer.

Milkshake adds some phases to the Rails initialization process. Below you can see all the added phases compared to a regular Rails initialization process.

Rails Rails with Milkshake
require frameworks require frameworks
extend frameworks with milkshake
load environment load environment
initialize database initialize database
take database snapshot
migrate database
load gems load gems
load plugins load plugins
load gem initializers
load application initializers load application initializers

Database agnostic Snapshots

Why and how I use production data in our development environment.At Mr. Henry we like to use real production data in our development envi...… Continue reading

Navigate between tabs like in TextMate

Published on April 26, 2009

Introducing GM [OUTDATED]

Published on January 18, 2009