A mini CMS
JavaScript Ruby
Switch branches/tags
Nothing to show
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
app
config
db
doc
lib
public
script
test
tmp/cache
vendor
.DS_Store
.gitignore
README
Rakefile

README

** miniCMS **

ABOUT
A mini CMS (Content Management System)

FEATURES
* one rails app that can spin up an arbitrary number of sites (via multiple mongrels)
* page/partial reuse between sites
* site_vars (like a partial, but sits in the database, good for smaller chunks of info)
* assets download management such that specific files can be served from specific sites
* an admin page where sites, pages, users, site_vars, can be controlled

BACKGROUND

I had a customer who had 7 very similar websites that were hosted on unique servers.
The sites all shared the same basic look but were tweaked a bit depending upon the marketing niche they were targeting.
Page updates were challenging since every site had to be updated individually in a repetitive fashion.  Also all pages were plain xhtml (no server side logic).
Now they have one server, one set of backups.  Everything is nice and DRY.

TECH
Rails 2.3.5
mysql
jquery and jqueryUI (in admin page)
authlogic


** OVERVIEW **


HOME CONTROLLER
The routes.rb file has been tweaked so that the home controller handles every page action.  This flattens the site and assumes that every url will be of the syntax http://sitename.com/:action

WORKFLOW OF A PAGE LOAD
The @site is determined in the application controller.
Then the home controller get's the request and renders the page based on the action that was requested and the site's page assignments.
If the action doesn't match any of the site's pages then a 404 is rendered.

SITE TEMPLATES
All site specific templates live in:
app/views/sites/SITE_NAME

SITE ATTRIBUTES
name - how site is identified.  Site templates folders need to have the same name
official_name - longer name to be used in the site content (a site_var could full this function too)
url - nice if you need to send emails and need to create links back 
layout - name of the layout to be used by the site
asset _folder - name of the site specific asset folder (see Assets)

Setting the site that mongrel is serving
There are two ways to specify the site that is being rendered:

1)  Pass in an environment when starting the mongrel process.  For example:
	script/server -e siteA_development
	script/server -e siteB_production

If a vanilla environment setting is passed (e.g development) then the first site in the site table is used.

2) Specify a site in the query string
	http://siteA.com/foo_action?site=siteB

Note: Option 2 can only be used if you haven't specified a site via option 1

ASSETS
One tricky aspect of having multiple sites running from one code base is that permanent things that might reside in app/public cannot differ from site to site (without some trickery).
To accomplish this, an assets folder can be created on the server outside of the app directory. 
Each site will have it's own folder within the asset directory.  When looking for assets, the cms will first check the site specific asset folder, then the general asset folder.
Each site has an asset_folder attribute indicating the name of this folder.
 
Capistrano's deploy.rb can be tweaked to create a new symbolic link to this assets folder on each deployment.  (see Deploying section)
Set this location in the site.rb model by modifying the ASSET_ROOT and ASSET_ROOT_SYMBOLIC_LINK vars.

PROTECTED PAGES
A page can be indicated as protected in the Admin > Sites > Edit section.  
If the page is protected then you can use the protected template to require a login before viewing those pages
If you want to utilize this you'll need to create a protected template in the root site.
This template would probably be the login form for your front end users.
If you don't want to use this just don't' set any of your pages to be protected.

UTILITY FUNCTIONS / HOW TO MIGRATE AN EXISTING SITE
My customer had lot's of existing .shtml pages that needed to be recreated as pages in the CMS.

There is a batch_rename.rb script in lib that will convert .shtml files to .html.erb

There are also several utility functions in the site.rb model to assist:
site.add_page(page_name) - add a single page to a site, creating the page record if necessary
site.remove_page(page_name)
site.populate_page_list_from_dir(dir) - read in a directories content of files, creating pages for each (if required) and then adding to site
site.depopulate_page_list_from_dir(dir) 
site.clone_to(target_site) - clone a whole site.  So take every page that's associated with a site and make the target_site have the same pages
site.undo_clone_to(target_site)
site.clone_page_sites(page, site_list) - clone a single page to another site
site.undo_clone_page_to_sites(page, site_list)

My Migration Workflow was:
use batch_rename to get all the html files to have the correct extension (.html.erb)
write numerous migrations that:
use site.populate_page_list_from_dir create all pages
use various util functions in migrations to get the sites cloned as required

ADMIN PAGE

The admin page can be accessed from any of the sites via:
http://SITE_NAME.com/admin

The default user/password is admin/foobar.

DEPLOYING

Using Capistrano, you'll need modify your deploy.rb so that each webserver spins up.
See /conf/deploy_sample.rb

Steps to Create a Site and bring it up

1. Create a site in the admin backend.  
2. If the site is a clone of another then do some migrations to clone it (or whatever you need)
3. Add a production and development environment file for the site.  Within /config/environments copy the existing production.rb and development.rb files and change their names to SITENAME_development.rb and SITENAME_production.rb
4.  Edit  config/database.yml .  Add two new yaml aliases: (see the example database_sample.yml)  
SITENAME_development: development
SITENAME_production: production 
5. If using mongrel_cluster, generate a mongrel_cluster config file for the site.    Otherwise you can just start the site using script/server -e SITENAME_development

SERVING THE SITES (MONGREL)

My setup has Apache acting as a reverse proxy and using proxy_balancer and mod_rewrite to send the requests to the appropriate mongrel cluster.
For more information on this sort of setup please see:
http://blog.codahale.com/2006/06/19/time-for-a-grown-up-server-rails-mongrel-apache-capistrano-and-you/

CONTRIBUTOR

miniCMS is brought to you by Sam Cooper <sam@chgworks.com>

LICENSE

(The MIT License)

Copyright © 2010

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
‘Software’), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED ‘AS IS’, WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.