Creating a Link Roll Extension
One of the most exciting aspects of Radiant is the support for extensions. Since Radiant is a “no-fluff” content management system there are a lot of features supported by other systems that will never make it into Radiant. I’ve tried to keep things clean and simple so that Radiant is easy to learn and easy to support. The trouble is, my opinion of what features constitute “fluff” and what features are absolutely necessary is probably different than your own. Extensions give you the opportunity to change this.
Using extensions you can customize nearly every aspect of Radiant. And because Radiant is made with Ruby on Rails, developing an extension is almost as easy as developing a regular Ruby on Rails application.
In this tutorial I want to help you get started with your first extension. We will cover:
- Using extension generators
- Creating a custom model and controller
- Running extension migrations
- Creating custom tags
I will assume that you already have the latest Radiant gem installed on your local computer and that you have a basic understanding of Ruby on Rails. If you have never used Ruby on Rails before please run through the Rolling with Rails tutorials (Part I, II, & III) before you begin.
Let’s create a test project. Open up a command prompt and “cd” to the appropriate directory, then execute the radiant
command to create a new project:
radiant -d sqlite3 path/to/new/project
As you can see I’ve chosen to use SQLite 3 as my database engine, but you are welcome to choose MySQL or PostgreSQL instead.
The radiant
command will create a skeleton for our new project and then output the following instructions:
== Installation and Setup
Once you have extracted the files into the directory where you would like to
install Radiant:
1. Create the MySQL/PostgreSQL/SQLite databases for your Web site. You only
need to create the "production" database, but you may also want to create
the "development" and "test" databases if you are developing extensions
or running tests.
2. Edit config/database.yml to taste.
3. Run the database bootstrap rake task:
% rake production db:bootstrap
(If you would like bootstrap your development database run `rake
development db:bootstrap`.)
4. Start it like a normal Rails application. To test execute:
% script/server -e production
And open your Web browser on port 3000 (http://localhost:3000). The
administrative interface is available at /admin/. By default the bootstrap
rake task creates a user called "admin" with a password of "radiant".
When using Radiant on a production system you may also need to set permissions
on the public and cache directories so that your Web server can access those
directories with the user that it runs under.
Once you've installed Radiant on your own Web site, be sure to add your name
and Web site to the list of radiant users:
http://wiki.radiantcms.org/Radiant_Users
If you’ve chosen to use SQLite 3 as your database engine for this tutorial you can ignore steps 1 and 2. Otherwise create all three databases for the development, production, and test environments and edit config/database.yml
to taste. Then run the bootstrap rake task for the production and development environments:
rake db:bootstrap
rake production db:bootstrap
Once you have bootstrapped both databases, start up the test server in production mode from the command line and verify that the site is running correctly before continuing:
script/server -e production
Now go to “http://localhost:3000/admin/” and login to verify that everything is working correctly.
Once you are logged in click the “Extensions” link in the upper right corner to see the extensions that are currently installed:
Radiant ships with three pre-installed extensions at the moment. The “Archive”, “Markdown” and “Textile” extensions. On the extensions screen you can view related information.
Now go back to the console and press Ctrl+C to stop the test server.
Let’s create our first extension. The extension we will be creating is one that will make it easy for us to manage a list of links on our Web site. To create a new extension you should use the extension generator. The format for the command is:
script/generate extension ExtensionName
In our case we will call our extension LinkRoll. At the command prompt type:
script/generate extension LinkRoll
You should see the following output:
create vendor/extensions/link_roll/app/controllers
create vendor/extensions/link_roll/app/helpers
create vendor/extensions/link_roll/app/models
create vendor/extensions/link_roll/app/views
create vendor/extensions/link_roll/db/migrate
create vendor/extensions/link_roll/lib/tasks
create vendor/extensions/link_roll/README
create vendor/extensions/link_roll/link_roll_extension.rb
create vendor/extensions/link_roll/lib/tasks/link_roll_extension_tasks.rake
create vendor/extensions/link_roll/spec/controllers
create vendor/extensions/link_roll/spec/models
create vendor/extensions/link_roll/spec/views
create vendor/extensions/link_roll/spec/helpers
create vendor/extensions/link_roll/Rakefile
create vendor/extensions/link_roll/spec/spec_helper.rb
create vendor/extensions/link_roll/spec/spec.opts
As you can see, the extension generator has created a skeleton extension for us in the vendor/extensions/link_roll folder. The extension we will create will be entirely contained in the link_roll folder. To use it in another project all we need to do is copy the link_roll folder into that project’s vendor/extensions folder.
Open up the “link_roll_extension.rb” file. It should look something like this:
# Uncomment this if you reference any of your controllers in activate
# require_dependency 'application'
class LinkRollExtension < Radiant::Extension
version "1.0"
description "Describe your extension here"
url "http://yourwebsite.com/link_roll"
# define_routes do |map|
# map.connect 'admin/link_roll/:action', :controller => 'admin/link_roll'
# end
def activate
# admin.tabs.add "Link Roll", "/admin/link_roll", :after => "Layouts", :visibility => [:all]
end
def deactivate
# admin.tabs.remove "Link Roll"
end
end
Let’s edit the attributes of the LinkRollExtension. The attributes are listed in the first part of the class definition. First, change the “description” attribute to:
Allows you to add a link roll to your Web site.
And change the “url” attribute to:
http://github.com/radiant/radiant-link-roll-extension/
We will deal with the other two attributes in a moment. For now, let’s start the server up again:
script/server -e production
Again, open your web browser up to “http://localhost:3000/admin/” and login. Click the “Extensions” link in the upper right corner. In the list of extensions you should now see the “Link Roll” extension:
Note that the description and the website correspond to the attributes that you just edited.
Let’s go back to the command prompt for a moment and generate our first model. Press Ctrl+C again to stop the test server. Type:
script/generate extension_model LinkRoll Link title:string url:string description:text
This should output:
exists app/models/
exists spec/models
create app/models/link.rb
create spec/models/link.rb
exists db/migrate
create db/migrate/001_create_links.rb
As you can see the extension_model generator takes several arguments. “LinkRoll” is the name of the extension that we want to add a model to. “Link” is the name of our new model. And the rest of the parameters are attribute:type formatted attributes of the new model.
If you look at the output of the command, you will notice that it generated:
- the file for the Link model
- the rspec test
- the migration
Open up the migration file (“vendor/extensions/link_roll/db/migrate/001_create_links.rb”). It should look like this:
class CreateLinks < ActiveRecord::Migration
def self.up
create_table :links do |t|
t.column :title, :string
t.column :url, :string
t.column :description, :text
t.timestamps
end
end
def self.down
drop_table :links
end
end
Note: The actual file name of the migration file might be different because it will contain the actual date/time in the filename
You can see that the migration is already setup to create a “links” table for the associated Links model object. Also note that the attributes on the Links model are configured to reflect the attributes that were originally passed into the extension_model generator command.
Let’s run the migrations for this model (be sure to run them on both the development and production databases):
rake db:migrate:extensions
rake production db:migrate:extensions
Note: You can safely ignore this for now, but: Later, if you want to migrate your database to a specific version of your extension’s schema (for example an earlier version to roll-back changes), you must use the migration task that was generated specifically for your extension, for example:
rake production radiant:extensions:link_roll:migrate VERSION=0
The version number corresponds to the number of your extension’s migration (file), not the version number in the schema_info
table.
Now that we have the appropriate model object setup for our link role, let’s create the associated controller. Run the following command:
script/generate extension_controller LinkRoll admin/links
This should output:
create app/controllers/admin
create app/helpers/admin
create app/views/admin/links
create spec/controllers/admin
create spec/helpers/admin
create spec/views/admin/links
create spec/controllers/admin/links_controller_spec.rb
create spec/helpers/admin/links_helper_spec.rb
create app/controllers/admin/links_controller.rb
create app/helpers/admin/links_helper.rb
If you look at the output of the command, you will notice that it generated:
- the Admin::LinksController
- the link controller helper
- the folder for the link controller views
- the RSpec files for controller and helper specifications
Also note that we put the LinksController in the Admin module because it will be part of the admin interface.
Open up the controller file now (“vendor/extensions/link_roll/app/controllers/admin/links_controller.rb”). It should look like this:
class Admin::LinksController < Admin::ApplicationController
end
In the Radiant codebase, there is a controller called the Admin::ResourceController
, which defines all of the actions required for a typical model. By making your LinksController inherit from this, instead of from the ApplicationController, you can get a lot of functionality for free. To make it work, you also need to specify the name of the Model which the controller should work with. This is done by declaring: model_class Link
.
Your LinksController should look something like this:
class Admin::LinksController < Admin::ResourceController
model_class Link
end
The actions defined in the Admin::ResourceController
require the following views: index, edit, new, _form and remove.
Create the following 5 files:
- link_roll/app/views/admin/links/index.html.erb
- link_roll/app/views/admin/links/new.html.erb
- link_roll/app/views/admin/links/edit.html.erb
- link_roll