Simpler than dirt: RESTful Dynamic CSS

— October 18, 2007 at 20:13 PDT


Way back when, I wrote about how to do Dirt Simple RCSS in Rails. Now that Rails 2.0 is upon us, it's time to get even simpler. With all the restful magic in Rails 2.0, you can get even simpler than dirt.

Let's assume you have a restful User resource. You've got your "map.resources" in routes.rb, a typical User model, and a Users controller with standard views like index and show. Now you want to generate user-specific css based on state in the user model.

1) Create a view template called "show.css.erb". For example:

p {
  color: <%= @user.color %>;
}

2) Add a css format option to the respond_to block in the show action of the UsersController. You only need the default behavior for the css format, since all you need to do is render the view.

def show
  @user = User.find(params[:id])
  respond_to do |format|
    format.html
    format.css
  end
end

You can see the dynamically generated css at a url like /users/1.css in your browser.

Here's how to use the stylesheet in a view, assuming you've set up a @user object:

<%= stylesheet_link_tag formatted_user_path(@user, "css") %>

Told you it was simple.

Note: Geoffrey "topfunky" Grosenbach also has a good article on dynamic CSS, which includes a nice screencast as well.

18 commentscss, rails, update

Comments
  1. Matt Swasey2007-10-18 21:13:59

    This didn't just go into 2.0 did it? Been in there hiding for a while?

  2. Daniel Fischer2007-10-18 21:39:50

    Awesome, this is really sexy! Thanks for the tip!

  3. Josh Susser2007-10-18 22:18:09

    Matt: The CSS mime type has been in the 2.0 trunk since revision 6159. This just all came together nicely as all the little changes meshed together. Nice testament to the synergy of Rails' feature set.

  4. topfunky2007-10-18 22:44:47

    There was once a bug where the Content-type header wouldn't be properly set, but that has been fixed, too, which makes this even easier.

  5. James O'Kelly2007-10-19 03:09:36

    Very sexy and easy indeed. Thanks for the tip Josh!

  6. curio2007-10-19 11:05:11

    Looks to me even more simple to make an inline declaration in application.erb.html, just after your stylesheetlinktag.

    Looks like :

    <% if @user do %> p { color: <%= @user.color %>; } <% end %>

  7. Josh Susser2007-10-19 15:05:29

    curio: Yes, you can also generate style information inline in a view or layout, which may be handy for very small bits of style information. I like the approach of generating a separate stylesheet file because then you can take advantage of both asset caching in the browswer and page caching in the Rails server.

  8. Aaron Patterson2007-10-22 22:01:39

    Doesn't this mean that you would have to query for @user twice?

  9. Nicolás Sanguinetti2007-10-22 22:16:43

    This is really cool :D

    @Aaron Patterson: yeah, but you can page-cache the css until the user changes it again.

  10. Richard White2007-10-31 00:13:58

    The problem I see with the presented solution is that it requires too much work ...

    • Add format.css to the action
    • Add the CSS file
    • Create a new layout and add my stylesheetlinktag there

    I'd like it more if there was a higher level of support for doing this, something that silently just works like the right Helpers being accessible to a view.

    Create a <%= dynamicstylesheetlink_tag %> that displays a link to the dynamic CSS ONLY IF one actually exists since returning 404's for assets is a no-go. I'd also want it to work without any changes to my action, in fact it should bypass actually calling the action all together probably in the form of a before filter.

    I smell a plugin :)

  11. Josh Susser2007-10-31 03:14:11

    Richard: Sounds like a lot more work to do it just once, but yeah, easier in the long run if you do it in a lot of apps. I also think the non-restful approach where you get the user_id from the session instead of the URL is fine too. Can you put support for both in your plugin? :-)

  12. Jim Neath2007-11-06 11:21:50

    Brilliant. I need to have a play around with this. I've been meaning to work on customisable layouts for users on one of my sites.

    This looks like a great starting point for it.

  13. Aphelion2007-11-15 04:28:38

    If you want truly beautiful CSS that... doesn't require conditional logic (seriously... erb might be a bit much here), then I would whole-heartedly suggest SASS, part of the HAML plugin. It has constants, math, and string concatenation. You can't tell me this example isn't beautiful:

    !font_family = "sans-serif" !mainfontsize = 1em

    main

    :font :family = !font_family :size = !mainfontsize h6 :font = italic "small-caps" bold (!mainfontsize + 0.1em) !font_family

    Plus it's not part of the view, the sass files are stored in public/stylesheets/sass and generate a similarly named css file in public/stylesheets only when the sass file changes. you use all the normal methods of including css in your page and don't have to worry about it.

  14. Aphelion2007-11-15 04:33:59

    ARGH! Defeated by markdown. sigh... read here instead: http://haml.hamptoncatlin.com/docs/rdoc/classes/Sass.html

  15. Alexander May2007-11-19 05:50:28

    For those of you using Komodo (and I know that is the minority), I have created a syntax highlighting plug-in for .rcss / .css.erb files. Enjoy.

    http://codingfrenzy.alexpmay.com/2007/11/syntax-coloring-for-dynamic-css.html

    Alex

  16. Jamal2007-11-21 17:20:19

    Hello there,

    The plugin simple_rcss is not found on the official website?

    http://svn.integralserver.com/plugins/simple_rcss

    Regards, Jamal

  17. Monica2007-12-05 23:38:37

    Hi guys,

    I've been trying to get this working but I'm missign something and I don't find what it is. I'm getting this error:

    no route found to match "/rcss/stylesheets/style.css" with {:method=>:get}

    Any idea/suggestion? Thanks a lot in advance!

    Monica

  18. Lar2007-12-12 18:06:52

    We use simple dynamic css in our apps, but I think it is time to take it to the next level. For me, support for nesting is a key feature missing, so I've been really itching to bring in sass but do not want to lose the ability to pull from the database. Could this technique be adapted to work with sass somehow?

    Ideally I would like to create style.sass.erb files and call them with render format.sass. Any ideas on implementing this?

Sorry, comments for this article are closed.