Sign In
Start Page | Recent Changes | All Pages | Orphan Pages | Junebug Help

Creating Radiant Extensions

One of the most exciting aspects of Radiant 0.6 is the support that has been added 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.

Creating a New Project

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://dev.radiantcms.org/radiant/wiki/RadiantUsers

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 your are logged in click the “Extensions” link in the upper right corner to see the extensions that are currently installed:

Radiant ships with two pre-installed extensions at the moment. The “Markdown” and “Textile” extensions. On the extensions screen you can enable or disable extensions and view related information.

Now go back to the console and press Ctrl+C to stop the test server.

Generating an Extension

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/test/fixtures
  create  vendor/extensions/link_roll/test/functional
  create  vendor/extensions/link_roll/test/unit
  create  vendor/extensions/link_roll/README
  create  vendor/extensions/link_roll/Rakefile
  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/test/test_helper.rb
  create  vendor/extensions/link_roll/test/functional/link_roll_extension_test.rb

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:


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://dev.radiantcms.org/radiant/browser/trunk/extensions/link_roll/"

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.

Generating a Model

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  test/unit/
exists  test/fixtures/
create  app/models/link.rb
create  test/unit/link_test.rb
create  test/fixtures/links.yml
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 unit test
  • the links fixture
  • the migration

Open up the migration file (“vendor/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
    end
  end

  def self.down
    drop_table :links
  end
end

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. )

Generating a Controller

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  test/functional/admin
  create  app/controllers/admin/links_controller.rb
  create  test/functional/admin/links_controller_test.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 functional test for the controller
  • the folder for the link controller views

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 < ApplicationController
    # Remove this line if your controller should only be accessible to users
    # that are logged in:
    no_login_required
  end

Since this is an admin controller for links, remove the no_login_required line. For this example we are going to use scaffolding to create a quick editing interface, but nothing would hinder you from creating your own actions and associated views just like you would in a normal Rails application.

To tell Rails that we want to use scaffolding for the Link model object insert the following line in the class body of the LinksController:


scaffold :link

Your LinksController should now look something like this:


class Admin::LinkController < ApplicationController
  scaffold :link
end

There are two remaining steps in order to get our LinkController to show up in the admin interface. First, we need to setup the routes definitions for the controller and second we need to add the associated tab to the admin interface.

To do this, open up the main extension file again (“vendor/extensions/link_roll/link_roll_extension.rb”). Change the define_routes block so that it looks like this:


define_routes do |map|
  map.connect 'admin/links/:action', :controller => 'admin/links'
end

Change the activate method so that it looks like this:


def activate
  admin.tabs.add "Links", "/admin/links", :before => "Layouts" 
end

And the deactivate method so that it looks like this:


def deactivate
  admin.tabs.remove "Links" 
end

You can define any number of routes in the define_routes block—just like you can in the routes.rb file of a normal Rails application.

The activate and deactivate methods are called for an extension whenever it is activated or deactivated. Normally these events occur when an application starts or when an extension is turned off through the admin interface. We are using the methods to add the “Links” tab before the “Layouts” tab.

The LinkRollExtension class should now look like this:


class LinkRollExtension < Radiant::Extension
  version "1.0" 
  description "Allows you to add a link roll to your Web site." 
  url "http://dev.radiantcms.org/radiant/browser/trunk/extensions/link_roll/" 

  define_routes do |map|
    map.connect 'admin/links/:action', :controller => 'admin/links'
  end

  def activate
    admin.tabs.add "Links", "/admin/links", :before => "Layouts" 
  end

  def deactivate
    admin.tabs.remove "Links" 
  end

end

If you setup your links controller and extension files correctly, you should now be able to create and edit new links from the admin interface. To test it out, run:


% script/server -e production

And go to “http://localhost:3000/admin” in your browser. Log in and click on the new “Links” tab. You’ll see a full featured editing interface for your new link roll (provided almost entirely through the builtin Rails scaffolding). Experiment a little with the interface. Add a couple of links to your link roll. Get a feel for how it all works together.

Creating Custom Tags

Now that we have an easy way to create and add links in the admin interface, it would be nice to add a couple of custom tags so that we can display links from our link roll on the Web site. Let’s do that now.

Create a new file in the “app/models” directory of your extension called “link_roll_tags.rb” and add the following code:


module LinkRollTags
  include Radiant::Taggable

  tag 'links' do |tag|
    tag.expand
  end

  tag 'links:each' do |tag|
    result = []
    Link.find(:all, :order => 'title ASC').each do |link|
      tag.locals.link = link
      result << tag.expand
    end
    result
  end

  tag 'links:each:link' do |tag|
    link = tag.locals.link
    %{<a href="#{link.url}" title="#{link.description}">#{link.title}</a>}
  end
end

Above, the LinkRollTags module includes the wonderful Radiant::Taggable module which adds the wonderful “tag” class method so that we can define our own tags in the module. (If you need access to Rails helpers in your tag, simply include them it the model: include TextHelper)

To make sure the tags are defined when our extension is activated, switch over to the main extension file (“link_roll_extension.rb”) and add the following line to the “activate” method:


Page.send :include, LinkRollTags

We’ve defined three tags for the Link module. In this tutorial we are not going to discuss the inner workings of the Radius tag DSL (for that you should read the Radius Quickstart guide), but suffice it to say that using the tag definitions above we can now write the following inside a page, layout, or snippet:


<ul>
<r:links:each>
  <li><r:link /></li>
</r:links:each>
</ul>

An have it output something like:

You can now use the code above to manage a list of favorite sites on your blog:

Conclusion

This concludes the Creating Radiant Extensions tutorial. I hope you’ve gotten a feel for the many things that are possible with Radiant extensions. Of course, the LinkRoll extension in this tutorial could use a lot more work to make it a truly polished extension that you can be proud of, but hopefully I’ve given you enough of a head start that you can take it from here.


Version 15 | Other versions: « older newer » current versions
Page last edited by rnhurt on May 09, 2008 08:52 AM (diff)