Wednesday, October 26, 2005

Full Theme Support in Rails, Revisited

OK, so after a short discussion and some experiments, I've realized that the Typo approach to themes has a lot more merit than I initially thought... For general use it still has some trouble areas, but that's nothing that can't be fixed.

I've created a new theme_generator that takes their general approach and makes it easy to leverage in any application. Even an existing one.

How to use it...

Usage is extremely easy. First, use the generator to create a default theme.

  ./script/generate theme default

(It doesn't have to be called 'default', it can be whatever you'd like)

This will create the main themes folder structure, the initial theme files for the theme ('default' in this case), and it creates the plugins/components needed to support themes.

Now you can use themes as easily as you do layouts. The following will use a layout named 'main' in the 'default' theme.

class ApplicationController < ActionController::Base
  layout 'main'
  theme 'default'
end

Here's an example of per-user themes:

class ApplicationController < ActionController::Base
  layout 'default'
  theme :get_user_theme

  def get_user_theme
    # This assumes, of course, your User has a 'theme' field
    return @session[:user].nil? ? 'default' : @session[:user].theme
  end
end

Differences from Typo themes...

I did take the liberty of tweaking of couple of things (beyond setting the theme in your controller). The main difference is that I changed the cached theme structure.

Before:

/public
  /images
    /theme
  /stylesheets
    /theme
  /javascript
    /theme

After:

/public
  /themes
    /[THEME_NAME]
      /images
      /stylesheets
      /javascript

What does this mean? For one thing, it's a lot easier to remove cached theme files... Just delete the public/themes folder.

Also, you should be using relative paths to images in your CSS. For example:

BODY {
  background: #FFF url(../images/page-bg.jpg) top left;
}

Requirements...

Update: theme_generator is now hosted on RubyForge.

The theme_generator requires Rails >= 0.14. The easiest way to install the theme_generator is by running:

  sudo gem install theme_generator

It's that simple. Feel free to install it and let me know what you think.

11 comments:

  1. [...] ion Update! There’s an updated version of the theme_generator. See the blog post or the [...]

    ReplyDelete
  2. Awesome work. One thing I did wonder about though (as I have a project coming up for which I want to be able to do this) is what would be the best way to allow the theming engine to create both AJAXified and plain HTML themes, from the same controllers/actions (In the interests of DRY)
    As an extreme example -- you have your pretty, spiffy, AJAXified version... and then an "ASCII-alike" version for all (none) of those Lynx users :)

    ReplyDelete
  3. Justin: Yes, you could use themes to do that. It would be a good reason to override the application views.
    You would, of course, have to make sure your controllers aren't hardcoded for posts and/or ajax calls. They'd need to be flexible enough to handle both. Which, with a little forethought, shouldn't be a big deal.

    ReplyDelete
  4. I noticed that Rails still reports view templates as missing unless a file is present in the original (app/views/controller) location. Even if just a blank file, it fixes the problem and uses the theme file. Although, it does not complain on partials.
    Is this a limitation of Rails or a bug in the theme system? Or perhaps it is meant to be this way so it can fall back to the original files if no themes are installed? Maybe even just an error on my side.
    Any insight on this is appreciated.
    By the way, great work.

    ReplyDelete
  5. Thanks Matt, this is just what I needed. I can't believe it was so easy! (Though I should be used to that with Rails by now.)

    ReplyDelete
  6. I can confirm the fact that a file needs to be in the original location too. This may not be a bad idea, for the default theme location anyway, if it's possible to say "theme nil" to take the default.
    Also, I wonder if components are themable...

    ReplyDelete
  7. I'm not sure if it's me doing something wrong, which would be very likely since I'm rather new to both Ruby and Rails, or if it's just a missing feature but doesn't the themes support subdirectories of images?
    I tried doing a few variants of , but they all ended up as broken links. As soon as I moved them out of the subdir they worked just perfectly. Other than this, the theme generator works just great :)

    ReplyDelete
  8. Yes I got the same problem than Niklas, but even with that it's fantastic! thanks a lot.

    ReplyDelete
  9. i suppose i should just try it, before i ask, but to save a bit of time:
    can this system run with shared partials?
    i would like to have a bunch of partials that represent formatted data that i could use in each of the themes..
    forms, news blocks, and that kinda thing..
    any ideas?
    thanks!

    ReplyDelete
  10. very cool realy thanks....evden eve nakliyat

    ReplyDelete