Amaze Your Friends With jQuery

I, along with several other EdgeCasers, spent the better part of last week at CodeMash in Sandusky, OH. The conference was a wonderful experience. The venue, the content, the people... they were all top notch. Don't be fooled by the cost (it's dirt cheap), this conference continues to stand out as one of the best around.

What made this year special to me, though, is that I was selected to speak. It was an honor and a blast. I was completely stunned when my jQuery talk drew a standing-room-only crowd. And even though the projector had no color and my hands were shaking too badly to drink my water, I still received lots of positive feedback. I feel good about the talk, and I hope I get the opportunity to give it again to improve upon it.

My slides are pretty bare. I'm not sure they'll make much sense without the accompanying talk. Nonetheless, several folks have asked for them, so here they are.

A few final notes about the conference...

It really hit me while I was there what incredible speakers I work with. If you missed Leon, Joe, or Jim, you owe it to yourself to find them the next time they speak.

This was also the first conference I've been to that brought in a rock band. Enter the Haggis was fantastic, and I'm really glad we decided to do this.

I can't say enough good things about CodeMash. Huge thanks is owed to all of the organizers and speakers. I can't wait for 2011!

From Camping to Sinatra + DataMapper + Mustache (part 1)

A little over two years ago, I wrote a quick prototype application to help me manage tenants and properties for our residential real estate business. As the guys here at EdgeCase will tell you, I took it just far enough to solve my main pain point. It was definitely geared toward one user, one particular user. One man's kludge hack is another man's workaround.

At that time, Camping was worth looking at as a quick prototyping framework. The functionality I needed came together fairly quickly, all together in one file hitting a sqlite3 database using Camping conventions at the time. Over time, I made a couple of tweaks to help me accomplish what I wanted to do. After using the app for a couple of months, it helped me answer the "Who owes us what?" and "Who's late?" questions very well.

In parts one and two of this article, I will dive into the process of porting the app from Camping to Sinatra + DataMapper + Mustache. In part three, I will make some summary conclusions.

The Goal

Why migrate the app? I decided to move this app to Sinatra et al. for a convergence of reasons.

  • I had a challenging time getting the Camping rental app to run again after updating the Camping gem. The challenge came because I updated the gem one day and ran the rental app many days later. I sat down to use the app and kaboom! It isn't production code and wasn't deployed anywhere.
  • Camping - Lack of continued development... I suspect that Camping is still used by many and there may be a community behind it. For me, today (or even last year) it isn't winning any mind share battles.
  • As a user, an idea for improving the app would come to mind. Not working with Camping on frequent basis made making these changes seem more difficult. Moving to a newer framework/platform in theory would make implementing these changes more exciting and worthwhile.
  • Mustache. I knew of Sinatra - other guys in the office had used it. I had heard of DataMapper and had wanted to check it out. Mustache came along at just the right time for me. When Chris announced it, the thought of porting the rental app over to Sinatra + DM + Mustache came immediately to mind.

As the idea percolated, thankfully, Chris added a sample Sinatra + Mustache app to GitHub. No excuses now.

The Action

I made heavy use of two templates available on GitHub: defunkt's own Mustache Sinatra Example and zapnap's Sinatra Template. Zapnap's template contains DataMapper, Rspec, and HAML ready to go. This may not be the correct or proper way, but I simply forked Chris's repo and then created a branch in which to start playing around with Mustache.

Mustache is "a framework-agnostic way to render logic-free views." Along the lines of unobtrusive javascript, removing logic from our views should make that logic more easily testable and therefore easier to maintain. Mustache is inspired by Google's ctemplate.

CTemplate is a simple but powerful template language for C++. It emphasizes separating logic from presentation: it is impossible to embed application logic in this template language.

If you agree with the sentiment about keeping logic out of your views, certainly using a template system that prevents logic will be very effective.

After playing around with Mustache a bit, it was time to do something a bit more challenging. This is where DataMapper and zapnap's Sinatra template came into the picture. As an experienced ActiveRecord user, I did my best to set aside my typical way of thinking about ORMs. First, add DataMapper and connect to my existing sqlite3 database.

require 'dm-core'

DataMapper.setup( :default, "sqlite3://#{Dir.pwd}/db/slummer.db" )

repository(:default).adapter.resource_naming_convention = lambda do |value|
  'slummer_' + Extlib::Inflection.pluralize(Extlib::Inflection.underscore(value)).gsub('/', '_')
end

class Tenant
  include DataMapper::Resource

  property :id,           Serial
  property :name,         String
  property :property,     String
  property :notes,        Text
  property :rent,         BigDecimal
  property :late_fee,     BigDecimal
  property :balance,      BigDecimal
  property :created_at,   DateTime
  property :updated_at,   DateTime
  property :last_paid_at, DateTime
end

DataMapper is highly flexible, allowing me to 'factor' out the slummer_ prefixes that Camping insisted on in the table names.

Listing the tenants seemed the best first step.

get '/tenants' do
  mustache :tenants
end

The simple 'stache:

<h1>{{title}}</h1>
<p>{{content}}</p>

The view:

class App
  module Views
    class Tenants < Mustache
      def title
        "The List of Tenants"
      end

      def content
        Tenant.all.map{|ten| ten.name}.join(" - -- - ")
      end
    end
  end
end

So, you may be thinking, wow!! baby steps?!? Stay with me. At this point, I wanted to see data from my database rendered through Mustache and Sinatra to my browser. I had no idea how to pass a specific object through to the Mustache template. I also wasn't yet familiar with what Mustache was expecting in order to produce a looping structure. Let's tackle both of those now.

Mustache loops between {{#tenants}} and {{/tenants}} when the tenants method returns a collection of objects. The collection (as of 0.4.0 or so) must be a collection of hashes with attributes as symbols for the keys.

{{#tenants}}
  <tr><td>{{name}}</td></tr>
{{/tenants}}

def tenants
  Tenant.all.map{|ten| {:name => ten.name}}
end

Now for passing an instance to the view. Certainly I do want to view the details about a particular tenant. Wiring up the Sinatra routing to correctly pass an instance variable may be trivial to you. It is now trivial to me. There were no solid examples. So, after digging and search through Merb, Sinatra, and DataMapper posts and forums, I found nothing. Digging a little deeper into the Mustache code base and the Mustache::Sinatra module specifically, I found the following would work:

get '/tenants/:id' do |id|
  @t = Tenant.get(id)
  mustache :tenant_view, {}, :t => @t
end

The Mustache view has access to @t. Now we are rolling. Check back for part two in a couple of days to read more.

Refactazor

Renaming a model in a large rails app? Refactazor is for you!

USAGE


$ refactazor template category

To rename Template to Category, for example. After you’ve made the code changes, you can get the body of a migration (if you renamed a model for example) by choosing ‘m’

This will dump out the body of a migration which should help take care of your table and column names affected.

Disclaimer

Do this in a new branch or something, whatever you do don’t use it on a project which is not in version control. You will probably regret it if you can’t undo anything. No warranty.

This script is to reduce the typing involved in such a refactor. It is not supposed to think for you. There will be more work for you to do after you’ve successfuly run it, this is just to speed the process up a bit.

I have, however, used this script to rename a model appearing in hundreds of files in a large app in a relatively short amount of time.

On Github

Speed up manual testing

jquery.populate

Manual testing your web app is a pain when you have lots of forms which need to be filled in. Not anymore!

Usage


  $('input').populate();

Inputs with a name containing ‘first_name’ will be filled in with a random first name, etc.

What if I want to add a new field type?


  $.populate.registerValues({
    favoriteColor: ['red', 'green', 'blue']
  });

Now favorite_color inputs will be filled in with a random color choice from [‘red’, ‘green’, ‘blue’]

I want to write a function to generate my field value

I won’t stop you!


  $.populate.registerValues({
    favoriteColor: function() {
      return 'red';
    }
  });

What if my new field depends on the value of another field?

I want the username to be the first name plus a number, or I want the password confirmation to be equal to the password, for example. (Both of these examples are already in the plugin)


  $.populate.registerValues({
    username: $.populate.dependency('firstName', function(firstname) {
      return firstname + Math.randomInt(100);
    }),
    passwordConfirmation: $.populate.is('password')
  });

Easy-peasy.

Download from Github

Managing source with a distributed team

Background

Many months ago we switched from using subversion to using git. A couple of our braver folks pushed this change through in the face of a few complaints from other team members. There is a learning curve. We got through this learning curve more quickly than I expected. Now looking back, I can see that the learning curve has several plateaus followed by steep inclines. In this post, I will describe where we were in our git scm process and where we are now. Hopefully this information will help you more fully embrace using git or at least help you think on and improve your process. If you think your process is better or you see anything in ours that is glaringly wrong or could use a tweak, please post a comment.

Then

After the initial learning curve, we settled into the use-git-like-we-used-svn process. Apart from pull-before-you-push, it was a free for all. What does this kind of process create? Well, a pair might tackle a user story for the client’s next release. The end of the day comes and they want to preserve their work. They make sure the tests pass. Commit and push. Fortunately, the repository did not have anyone else’s changes. They go home comfortable that the code changes will survive if their laptop or pairing station has a catastrophic disk failure.

The catch. The catch is they haven’t completed the feature. Maybe they will complete it tomorrow and the client will accept it before the next release. Then again, it is nearly guaranteed that we will want to deploy a feature release or a maintenance release before some feature is fully implemented.

At that point, we decided to create a remote branch for production and deploy from that branch. This sounded like a good choice. It did help us segregate changes ready for release and changes that were works in process. If you are currently using git and using it more to its full capability, you are probably smirking or cringing as you read this.

We cherry-picked and merged changes from master to production in preparation for deployment. This prep process was sometimes easy and straightforward and sometimes terrifying. Regardless, the final result was a production branch and a master branch that often contained the same code, but had a wildly varying commit history.

The preparation for some releases became excruciating. Even if preparing the release went smoothly, over time, this step in our process became a significant smell that begged to be addressed.

Now

After a bit of research and poking and prodding of our current repository, we have settled on the following process. Assume that there are no local modified files and no staged changes. Assume that the local tracking branches are up-to-date with the remotes that they track.

Bug or Feature

  1. Create a local branch from the production branch.
  2. Write tests and implement features commiting locally along the way.
  3. Clean up the commits using git rebase --interactive. This is helpful in taking several commits and squashing them into a single commit for the feature.
  4. Publish the local feature branch to a remote repository. The grb gem is a handy tool to help you work with remote branches. If we have a particularly urgent bug, we will likely skip this step and stage the fix for review by the client. It is more common though to publish to a remote to share the code with the rest of the team.
  5. Repeat No. 3 and No. 4 until the feature is ready for delivery or the bug is fixed. If the feature is large or the ultimate deliverable is a set of features for a particular release, each pair should interact with the remote in the standard way. The standard way is to git fetch the remote and rebase or merge in any changes before pushing your commits back to the remote.
  6. The feature branch can be rebased to production to keep it up-to-date with other changes. Coordinate the rebase with the team, as they will need to set up a new tracking branch.
  7. With the feature or set of features ready for deliver, we merge the branch down onto a staging branch for deployment to a client acceptance server.
  8. If the features are rejected, we are back to No. 3 and No. 4 above.
  9. After the features are accepted, we prepare it for a deployment by rebasing the local branch against production and then merging that branch back onto production.
  10. If for some reason, we need to work on the branch after it has been rebased, we will git push --force the rebased version to the remote after confirming with the team that no one is in process of making changes.

NOTE: Please only use git push --force if you really know what you are doing!!

It is worth stating that we run the test suite locally and on our CI server throughout this process.

Good/Bad/Lessons learned…

We are using this process on small team distributed projects. Prepping for and deploying releases has become almost trivial. This could simply be improvement that we experience by fixing a problem we caused. In any case, the repository history is much cleaner.

There is definitely a lot to learn in using git in your particular process. We are looking forward to continuing to improve our source control maintenance process.

UPDATE

A couple clarifying points…

  • production is the branch on which we want to keep a clean history. We also use a staging branch to collect features and bug fixes for deployment to the staging server. Your master may well be used as either the staging branch or the production branch. In the process above, we do not commit to master or staging or production directly. We simply merge in the features that are needed for a particular staging or production deployment.
  • Using this process, you will invariable rebase a feature branch to merge it into production prior to deploying a release. At this point, we typically delete the remote feature branch. Any additional work that comes up related to that feature can go through the entire process of obtaining a new branch off of production.

Your Rails Are Rusty - My eRubyCon Slides

Here are the slides from my talk today. I think it went pretty well.

Your Rails Are Rusty

Make Ajax File Uploads Sexy (screencast)

Last week I showed you how to perform file uploads via Ajax, but the result was too ugly for my taste. Today we're going to make it sexy. Check it out.

The source code for the example app is here.

Next week I plan to dive into using Flash to enable selecting and uploading mutiple files with progress indication. Stay tuned.

Ajax File Uploads Made Easy (screencast)

Here is my second screencast for the EC blog, this time talking about Ajax file uploads in Rails using jQuery. Let me know what you think in the comments.

A Non-Flash version is available here. The plugin discussed is on Github.

update: I decided to turn this into a series of screencasts on how to handle file uploads on the client side. Part two is now available, which builds on this example.

A Rant About Testing

Time to stir up some controversy. It’s been a while since I’ve posted, so why not come back with a bang. Disclaimer, though: these are only the opinions of me, Adam McCrea, and not of EdgeCase.

TATFT

There’s a meme going around for a while that’s gained a lot of popularity, and I for one would like to say that I do not, nor do I have any desire to Test All The Time. Being religious about testing is a recipe for brittle tests, wasted effort, and a false sense of security. I’d rather shift from religion to pragmatism. This means thinking hard about what and when we test.

In a few recent projects, I’ve begun heavy integration testing. No, I’m not breaking any new ground, but the fact is prior to these recent projects, I had no integration tests. I was a bad, bad little programmer. That aside, I have to say that it’s been incredibly eye-opening.

I like to test as far up the stack as I can, getting as close as possible to the end user. Right now that means using Webrat to mimic actual clicks and form interaction to navigate the app. Sticking to this approach, I can change the internals of the app however I want as long as the generated HTML for links and form fields remains untouched. If you had told me a few months back that I could substantially refactor my code and not change one test, I would have thought you were crazy. But integration tests make that possible.

Less testing

But how does that reduce waste? For starters, I no longer write controller (or view) tests. And neither should you. Seriously, just stop. You’re not only wasting your time, but also every future developer who touches that code and has to maintain your useless tests. This assumes two things: that you’re thoroughly integration testing your app, and that your controllers are as skinny as possible. If you still think you need controller tests, you’ve probably got crap in your controllers that shouldn’t be there. Get it out, and stop writing those tests.

I’ll proudly admit that I’m also testing my models a lot less. Seriously, what’s the point of testing things like attribute readers/writers and associations if I’ve got a full suite of integration tests? If my comments don’t belong to posts, I’ll get yelled at, and it’s not going to take long to pinpoint the problem. So, I’m really only unit testing substantial model and helper methods. Everything else gets hit at the integration level only.

What about coverage?

I still think coverage is important, but only at the integration level. Whether or not a piece of code is unit tested is purely subjective, but every line of code must be tested from the point of view that matters most – the user’s. 100% integration test coverage is no guarantee that you’ll catch every possible bug, of course, but anything less would indicate that you wrote some code without thinking about how it will be used.

So is Cucumber the answer?

Honestly, it just doesn’t matter. Just test your code from as far up the stack as possible using whatever tool you prefer. Cucumber, Rails integration tests, Selenium, well-trained monkeys, whatever. Go for it. I do like Cucumber, though, so it’s certainly worth a try if you’re new to full-stack testing.

Ideally, JavaScript would be included in these tests, I just haven’t found a solution yet that makes it practical. It would require a masochist to get 100% coverage with Selenium, but Culerity is one promising option that has popped up. I haven’t had a chance to check it out, though.

This approach certainly isn’t for everyone, but the current wave of TATFT is in desperate need of a counterpoint. If you like to use unit tests as a way to design your code, you probably think I’m way off base. That’s fine. We don’t all have to play by the same rules. Hell, even I still TDD, just not at the unit level. The point here is to make sure you’re very conscious of what, when, and why you test, and that you’re getting enough value from them to justify the time spent.

Bookmarklets 101

Last week I showed you a bookmarklet that lets you edit your CSS live in any browser. Today, I want to dive into the details of how to create a bookmarklet. But first, the basics:

What is a bookmarklet?

A bookmarklet is a small snippet of JavaScript crammed into a URL. Nothing else. That's not very helpful, though, is it? All it means is this: instead of using the http: or ftp: protocol for a URL, we use the javascript: protocol. And when this URL is invoked (perhaps by clicking a bookmark in your browser's bookmark toolbar) the remainder of the URL is executed as JavaScript. What this means is that we can execute any arbitrary JavaScript within the context of any site we please. And we can package it so that it can be shared and reused easily. But...

What is the point?

In general a bookmarklet will either alter the current page in some way, or make use of the context of the current page in concert with some other service. Some examples of the former are edit CSS, jQuerify, Firebug Lite, and 960gs grid overlay. These are usually only useful to developers. Some examples of the latter are URL shorteners, post to delicious, Amazon wishlist, and Instapaper. These are much more useful to consumers. Both kinds of bookmarks use the same technology, though, so the approach to developing them is basically the same.

The "Hello World" bookmarklet

Create a bookmark, and give it the following URL:

javascript:alert('hello%20world');

Now click the bookmark. Yep, that's all there is to it. Notice that we replaced the space with %20. That's important, and there are a few more rules that we need to keep in mind when creating bookmarklets.

Gotchas & Tips

URL length limit

I'm not sure what the definitive answer is on this. IE is (unsurprisingly) the limiting factor here, but I've heard conflicting information on what the actual limit is. I haven't bothered to test it since that would mean firing up Windows and opening IE, which I avoid at all costs. So, just keep it really really short, m'kay?

Cheat the URL limit

Most bookmarklets try to do way more than is possible within the URL limit I just described, so of course there is a way to cheat the rule. Just host an external JS file that gets dynamically required by your bookmarklet. Here is an example. The bookmarklet just appends a SCRIPT tag into the HEAD of the document, which requests and executes the external JS file.

Don't return a value

If your bookmarklet code returns a value, that value will find it's way to the browser's address bar. This is most likely not what you want, so you have two weapons to use against this. You can append a void() call at the end of your JS code:

someCode();void(0);

Or you can wrap your JS in an anonymous function. The added benefit here is that any variables you define are not polluting the global scope:

function(){someCode()}();

Don't depend on a JS library

Probably an obvious one, but you can't assume that jQuery, Prototype, or any other library is included in the page where your bookmarklet will eventually be run. I got around this in my Edit CSS bookmarklet by dynamically including jQuery and running it in noConflict mode. See the code for that here.

Next steps

If you want to write a bookmarklet that integrates with a Rails application, definitely check out John Nunemaker's screencast. Also dig into the bookmarklets that I linked to earlier in the article. If you have a favorite bookmarklet or want to know more about bookmarklets, please join the discussion below.

Edit CSS in Any Browser With the Click of a Button

So, a few weeks back I showed you how you could see your CSS changes in real-time in any browser. That was cool and all, but I haven’t found myself using it simply because of the convenience factor. The script (along with jQuery) had to be included in the page, whereas I could just fire up Web Developer Toolbar in an instant.

Today I’m introducing the bookmarklet version of that same script. It no longer requires jQuery, so just drag the link below up to your bookmark toolbar, and you’ll have this functionality one click away.

Edit CSS

I’ve also put together a short (3-minute) demo below. Enjoy.

Non-Flash version of screencast is available here (the Files and Links section in the sidebar).

The source for this is on Github, so please add issues there and fork away.

Best CMS For Developers? Rails.

The site you’re looking at right now (unless you’re reading from RSS) is old, ugly, and busted. Yes, the EdgeCase site – and blog – are in desperate need of an overhaul. While @nummi kicks around some design ideas, I’ve started looking into how to power our future home on the web.

Our needs are pretty simple. We need a collection of pseudo-static pages (occasional updates, but with some dynamic content), and a blog. This sounds like a simple CMS to me, and CMS solutions are supposed to make sites like this completely painless, right?

Yes, I am that delusional.

You see, I’ve never actually used a CMS. Everything we’ve built at EdgeCase has been far too custom to be considered a CMS, so until last Friday, I’d really only heard about them. Unfortunately, what I discovered after looking at some popular Ruby CMS solutions (Radiant and BrowserCMS) is that I hate CMS systems.

A CMS might make a lot of sense for a business of non-techies – regular folks who need to manage their content without calling up the “web guy”. But that’s certainly not us. We’re an entire company of “web guys”. At this point you might be thinking I’m ignorant for not realizing we’re outside the target audience for a CMS, and you’re right. But I didn’t realize this, so I’m going to rant for a bit on why CMS systems suck for developers.

The problem is that the benefits regular users get from a CMS just don’t apply to developers, and in fact they often cripple us. Take the most obvious CMS feature of editing your site content within a browser. Is there a developer out there who is as comfortable in an HTML textarea or a Word-like WYSIWYG as they are in their preferred text editor? But really this is the tip of the iceberg, a minor issue that I can get over, and I also can’t deny the convenience of committing a content change with the click of a single submit button.

But going a step further, most CMS systems also make the templates available for editing within a browser. This is where real pain sets in for me, and for two reasons: bastardized templating languages, and lack of a real editor. As a Rails developer, I’m very comfortable with ERB, and even more so with HAML. I should not have to learn a new templating language just to build my simple website. And regardless of which language I use, I simply don’t have the patience to code HTML in a textarea. I may not be a fan of editor wars, but I at least need an actual text editor if I’m building a website.

Other CMS niceties… Content versioning? If the content is part of the code base, I get that for free with Git. Permissions? Our needs are simple – if you have access to edit the code, you have access to edit the content. Plugins? Rails certainly has plenty of plugins, and with Rails 2.3 supporting Rails Engines and Rack middleware, the possibilities are endless.

So where does this rant leave me for the EdgeCase site? A Rails app, of course – custom built, because I’m not convinced that anything pre-built is actually going to make my life easier.

For the blog component of the site, I’ve got a lot of options to explore. I could, of course, build something from scratch. This might not be a bad idea, since our needs are pretty simple. But there are also some blog engines out there that could be worth checking out: Marley and Scanty are a couple that look very interesting. I’d love to see an engine-style Rails plugin that provides a blog, but I haven’t come across one yet. Perhaps we’ll just have to build one ourselves. After all, a blog can be built in 15 minutes, right?

Follow me on Twitter if you want updates on what direction we take. Or you could just wait for the redesigned EdgeCase site. It should arrive on or before 2011.

Debugging jQuery Events

When an app reaches a certain level of complexity, particularly with regards to JavaScript, you’re probably going to have events bound and triggered all over the place. Events are a powerful thing, but they can be a bitch to debug.

This didn’t use to be the case. Back when we were all setting events inline, all you had to do was look at the HTML to know what events are bound to to an element:


<form onsubmit="if (!validate(this)) return false;">...</form>

I’m going to give you the benefit of the doubt that you’re not doing this anymore. I’ve been writing (and evangelizing) unobtrusive JavaScript for years now, but I have to admit this is one aspect of inline event handling that I really miss.

Take this scenario:

You’ve given a form a class of “ajax”, and you’ve got the following jQuery in place to make sure that all forms with a class of “ajax” are submitted via Ajax.


$('form.ajax').ajaxForm();

Unfortunately, when you try to submit the form, nothing happens. Nothing at all. No Ajax. No form post. No errors.

What do you do?

In the past, I’d start sticking console.log statements in my JS, or maybe debugging directly in Firebug. Recently, though, I found a better way. I was fumbling my way through the event code in jQuery, and I discovered that event data is easily accessible through the element itself. Here is how a Firebug session might look as I dig into these events:

The first thing I do is grab the form element, and see what it has in the “events” data (if you’ve never messed with the data() method before, you should ). I see that there is at least one handler assigned to the “submit” event, so I iterate through each of them and call toString() on each function so I can see the actual code.

The second function listed is the actual code for the ajaxForm() method, so it’s cool. The first one, though, is the culprit I’m looking for. This handler is being bound to my form’s submit event somewhere, and it’s calling stopImmediatePropagation() which prevents any other handlers from being called. Then it’s just a matter of searching for that exact code in the project, removing or fixing it, and beating the developer who put it there (which is usually me).

I admit this is not as easy as glancing at the HTML and seeing the event handler code inline, but it at least gets the job done. Any other tips for debugging events, please share in the comments!

Show Off Your Mockups

Whether you’re a do-it-all designer/developer or if those roles are separate, odds are your typical workflow involves taking a static HTML mockup and wiring it up with all your crazy codes.

So, maybe you’ve got an HTML file with a bunch of dummy data in it that you need to demo for a client. You probably stuck it somewhere in /public because it’s easy. It’s probably got a list of copy-and-pasted garbage in there, too, so it looks like a “real” page with lots of data. And of course there’s the header, footer, and other layout cruft you had to add so it fits the look of the rest of the application.

You’ve gotten some feedback from your client, and made some tweaks to the design. It’s looking pretty good. You’re feeling pretty good. Now it’s time to wire that page into the application.

Still feeling good?

This is the part that sounds so easy until you have to dive in and do it. It’s painful and tedious, but the good news is, it doesn’t have to be. It’s time to let Showoff come to your rescue.


  script/plugin install git://github.com/adamlogic/showoff.git
  script/generate showoff

This plugin is an extraction from a recent project where I got tired of dealing with this same old scenario. I wanted a place where I could stick mockups without thinking about it. I wanted my mockups to use the same layout, CSS, and JavaScript that the rest of my application does. I wanted to be able to use Ruby in my mockups to have access to looping, variables, and data generation (Faker). I wanted partials in my mockups. And I wanted a single place to go where the client and development team could see all of the mockups.

After installing and generating Showoff, navigate to /mockups in your app to see some examples. To make your own, just create a file in app/views/mockups. You can use HTML, ERB, or any other templating language (such as HAML) that your application supports. Yes, it really is that simple.

Here is an example in a fresh Rails app with Ryan Bates’ nifty_layout applied:

I’m sure Showoff isn’t the first plugin to attempt to simplify this process, but I can tell you that it’s working really well for us. Check it out and let us know what you think.

Update: I should also add that this plugin requires Rails 2.3, since it makes use of an engine-style plugin. This basically lets you embed one “mini app” inside of your main app. It’s pretty powerful, and I’ll write more about my experience of extracting this plugin in a a future post.

See Your CSS Changes in Real-Time in Any Browser

I’ve wanted to scratch this itch for a while, and this morning I decided to steal a few hours to give it a shot. Most of my CSS authoring and editing takes place in Firefox, using Web Developer Toolbar. For me, seeing CSS rendered in real-time is the only way to write it. (This is one reason I had to pass on Sass, even though I love Haml, but that’s a topic for another time.)

This has come major shortcomings, though, since Web Developer Toolbar is not intended to be a text editor (nor should it be). The biggest pain is saving your changes. A save button is provided, but you have to navigate through your filesystem to find the right location. If you’re lucky this location will be remembered next time you save. Support for find and undo is shaky at best, and as a Vim user, there about a thousand other features that I “need” in my text editor.

The other problem with Web Developer Toolbar is that it is Firefox-specific. On days that I have to debug my CSS in IE (my “hating life” days), I’m back to the refresh button.

Today I may have found a solution.

I say “may” because I literally just wrote this. I’ve tested it a little bit, but I can’t claim to have used it for real project work. Nonetheless, I’m pretty damn excited. Twenty minutes ago I had three browsers open (IE, Safari, and Firefox), and saw all three of them update as I saved my CSS file in Vim.

Check it out on Github and let me know what you think. As long as you’re using jQuery, using it is as simple as dropping in the .js file and calling $.autoUpdateStylesheets.

My next steps are to pull this into a bookmarklet and remove the jQuery dependency. Then it’s just a matter of pushing a button and editing away in your favorite text editor. Enjoy.

(oh, and this should work with Sass, too, so I guess it’s time for me to take another look.)