Introducing Togo
Togo is a CMS framework. The goal of Togo is to be a modular system that can be used with any Ruby ORM framework, giving you a complete CMS right out of the box. It is built to be as independent as possible from other web frameworks such as Rails or Sinatra, and only needs Rack and your choice of HTTP server to run (such as thin, mongrel or webrick). Togo is focused only on making a quick and easy way to manage content, and is less about integrating into your existing web application.
Installation
gem install togo
Example Application
An example application is available: http://github.com/mattking17/Togo-Example-App
Tutorial
Togo works by a simply including a line in your model definition (currently, Togo only works for DataMapper). By including Togo in your model, it will be automatically integrated into the Togo admin application, giving you all the CRUD actions as well as listing and search. It even works with associations.
Setting up a simple application
We'll use a combination of Sinatra, DataMapper and Sqlite for our tutorial. You actually don't need Sinatra to run the Togo admin application, however this gives a good idea of how Togo can be used in conjuction with an existing project.
You'll need the following gems installed:
dm-core dm-serializer sinatra dm-sqlite3-adapter
Next, make a directory for your project like so:
togo-example/
|
-- models/
|
-- views/
|
-- init.rb
|
-- app.rb
|
-- example.db
Set up your models
Inside the models directory, create a blog_entry.rb and comment.rb file, and drop in the following:
#blog_entry.rb:
class BlogEntry
include DataMapper::Resource
include Togo::DataMapper::Model
property :id, Serial
property :title, String
property :body, Text
property :date, DateTime
has n, :comments
end
#comment.rb:
class Comment
include DataMapper::Resource
include Togo::DataMapper::Model
property :id, Serial
property :name, String
property :email, String
property :body, Text
property :date, DateTime
property :blog_entry_id, Integer
belongs_to :blog_entry
end
Create an init file
Togo doesn't set up your database connection or initialize anything needed by your models for you, so you'll have to tell it what to do. There are a couple ways of doing it: put the code in a file of your choice and tell Togo to include it at runtime, or place the code in a file called togo-admin-config.rb in the same directory that you will run Togo from.
In this example, we'll put our initialization in the init.rb file and tell Togo to include it at boot time.
#init.rb:
SITE_ROOT = File.dirname(File.expand_path(__FILE__))
%w(dm-core dm-migrations togo).each{|l| require l}
Dir.glob(File.join(SITE_ROOT,'models','*.rb')).each{|f| require f}
DataMapper::Logger.new(STDOUT, :debug)
DataMapper.setup(:default, "sqlite3://#{Dir.pwd}/example.db")
DataMapper.auto_upgrade!
You're ready to start using Togo
At this point you can fire up the Togo admin application. Remember we have to include our init.rb file:
togo-admin -r init.rb
Open up http://0.0.0.0:8080 in your browser and have a blast! Have a look at our CMS User's Guide for a walkthrough of base CMS functionality (Coming Soon).
Customizing Togo
Togo is set up to work with sensible defaults out of the box, but you can customize what fields are used, what order they appear, and even use your own templates to show fields when editing or creating content.
Telling Togo which fields to use
By default Togo will look at your model and include all available fields in the admin, but you can also tell it specifically which fields to use for both the list view and form view.
Changing the list view
If you only want the title and date field to appear in the list view of blog entries, just add in to your model definition:
class BlogEntry
include DataMapper::Resource
include Togo::DataMapper::Model
... snipped ...
list_properties :title, :date
end
Togo will display the fields in the order given. So if you wanted date first some reason, you could just do
list_properties :date, :title
And date will be listed in the first column.
Changing the form view (New and Edit views)
Just as you can change the list view fields, you can also tell Togo which fields to show in form view and in which order.
class BlogEntry
include DataMapper::Resource
include Togo::DataMapper::Model
... snipped ...
list_properties :title, :date
form_properties :title, :date, :body
end
Associations also can be used in list and form property declarations:
class BlogEntry
include DataMapper::Resource
include Togo::DataMapper::Model
... snipped ...
list_properties :title, :date
form_properties :title, :date, :body, :comments
end
Togo also allows for displaying values returned from instance methods on your model. This opens up customization of the list display even further.
class BlogEntry
include DataMapper::Resource
include Togo::DataMapper::Model
... snipped ...
list_properties :title, :date, :number_of_comments
form_properties :title, :date, :body, :comments
def number_of_comments
comments.count
end
end
Configuring properties
There are some options you can change on each field individually by using the configure_property declaration.
Here you can customize the label:
class BlogEntry
include DataMapper::Resource
include Togo::DataMapper::Model
... snipped ...
list_properties :title, :date
form_properties :title, :date, :body
configure_property :title, :label => "Title (keep it short and sweet)"
end
Each property type has it's own default form template that can be overridden simply by specifying a full path to the template (only ERB is currently supported):
class BlogEntry
include DataMapper::Resource
include Togo::DataMapper::Model
... snipped ...
list_properties :title, :date
form_properties :title, :date, :body
configure_property :title, :label => "Title (keep it short and sweet)"
configure_property :body, :template => File.join(SITE_ROOT, 'views', 'custom_body.erb')
end
Note we used the SITE_ROOT constant we defined in the init.rb file, how you get the full path to your template may vary depending on your setup.
See the Writing a Form Template Guide for more information. (Coming Soon)
Configuring Togo::Admin
There are currently only a couple configuration options for Togo Admin which affect runtime, but you can also pass in any arbitrary configuration parameters and access them through custom templates in a global config hash. In our example, let's open init.rb and configure Togo::Admin:
#init.rb:
SITE_ROOT = File.dirname(File.expand_path(__FILE__))
... snipped ...
Togo::Admin.configure({:site_title => "My Admin Title", :my_custom_config => "Custom Config Value"})
If you had a custom template for your property and wanted to access :my_custom_config:
<%= config[:my_custom_config] %>
Authentication
By default Togo is not protected by an authentication method. If you're going to run Togo on a public web server, you'll most likely want to protect it. Luckily you can tell Togo to use any object you desire to autenticate against.
First, define any object that responds to two methods:
self.authenticate(username, password)
A class method that Togo Admin will call, passing in a username and password. If successful, You must pass back an instance of your object with a property called authenticated? set to true. If authentication fails, you can still pass back an instance of your object, but with authenticated? returning false, or can return nil.
authenticated?
What Togo Admin will ask an instance of your object before every request. Must return true or false.
If the Togo Admin authenticates the user successfully, it will store the instance of that object in the session and check it before each request to see if the user is authenticated or not.
Example User object for authentication
Here is an trivial example using a DataMapper object to authenticate a user:
class User
include DataMapper::Resource
property :id, Serial
property :username, String
property :password, String
attr_accessor :authenticated
def authenticated?
authenticated || false
end
def self.authenticate(u, p)
u = first(:username => u, :password => p)
u.authenticated = true if u
u
end
end
Note that the object does not have to have the Togo Model module included to work, unless you want it to.
Enabling Authentication
Finally tell Togo Admin to authenticate against your User object by configuring the Togo::Admin application at runtime, either in your init.rb or togo-admin-config.rb file, like so:
Togo::Admin.configure({:auth_model => User})
It's up to you how to to authenticate the user: Local Database, LDAP, Kerberos, etc.