View Sandboxes for Rails

Designing HTML views is an iterative, interactive process by nature. And anything that slows down the iterations, slows down development.

I was working on a form recently where the steps to show it went something like this:

  1. Go to the home page
  2. Log in
  3. Click “New Thingit” (domain terms have been changed to protect the innocent)
  4. Click “Edit” on the Thingit
  5. Click “Settings”
  6. Click “Enable Facebook integration”
  7. Click “Save”
  8. Click “New Wodget”
  9. Fill in the “New Wodget” form
  10. Click “Save”
  11. Click “Edit” on the saved wodget

All this just to get to the “Edit” view of a Wodget. Once you got this far the iterations were a little tighter, but because the forms were presented via AJAX, you couldn’t just hit F5 to refresh the form after making a view change. You still had to take a few steps:

  1. Click “Cancel”
  2. Click “Edit”

All this rigmarole got in the way of quickly seeing the results of view tweaks.

The way I finally decided to address the issue was to create a “view sandbox” inside the app where I could easily fiddle with arbitrary views.

I created a routing section for the sandbox which would only be enabled in the “development” environment:

if Rails.env.development? 
  match 'sandbox/:action' => 'sandbox' 
end

Then I created a very basic SandboxController, with an action dedicated to the view I wanted to play with:

class SandboxController < ApplicationController
  helper 'thingit'
  helper 'wodget'
  
  layout 'application'

  def edit_wodget
    @thingit = Thingit.find_or_create_by_name("SANDBOX_THINGIT") do |thingit|
      thingit.wodgets.create(...)
    end
    @wodget = @thingit.wodgets.first
  end
end

The controller action created just enough example model data to keep the view happy.

Finally, I created a views/sandbox/edit_wodget.html.haml view corresponding to the action, which simply included the Wodget form partial.

With this in place, I was able to simply navigate to http://localhost:3000/sandbox/edit_wodget to experiment with changes to the view, hitting reload when I wanted to see the effect.

Maybe there’s a better way to do this, and if there is I hope you’ll clue me in. I present this in case anyone else has run into a situation where the change->preview->change roundtrip is just too darn slow.

14 comments

  1. Wow, awesome technique. Thanks for sharing it.

    What you did illustrates the difference between the “slow easy” way and the “fast hard” way. It took some thinking to set up the sandbox, and it would have been easier just to train your fingers to go through all the steps. Instead, you thought more deeply about the problem and saved all kinds of time and effort.

    1. I was trying to explain to a friend the other day that for me “flow” (deep, productive concentration) more often than not looks from the outside like a man leaning back in his chair staring into space. I find the shortest path from point A to point B often involves thinking a lot and typing very little.

  2. Great tip, Avdi. We have something just like this where I work. We actually use it to enable another workflow as well:

    • Our UX guy can create a HAML template in the right directory, load it up in his browser, and get the content and styles right with the benefit of having all the CSS and layout/helpers setup just like they will be on the final page.
    • When developers are ready, we move the template from the “sandbox” view directory into place after we’ve create a route, controller, etc.

    -Bryan

    1. Bryan I want to be a UX guy where you work…

      I tried to explain the HTML+CSS development process to our .NET guys on a project where I was the UX guy. The site was liquid layout, client themeable, and supported both browser native font-sizing as well as buttons on the site for users to set font-size. Our client base is 40% IE6, the rest IE7-9 and FF. I prototyped the front-end w/ Ramaze+HAML+SASS, and needed 2-4 second cycle times to be efficient since each component and page needed to be checked on 5 browsers * 3 font-sizes * window width from 800-1280px.

      When we moved to the dev phase the .NET devs didn’t seem to think it a big deal that markup was strewn about views, controllers, models, javascript, XML config, and the DB. To make changes to HTML that is (inexplicably) in the models or controllers the process was 1) stop server 2) build 3) start server, which took about 3 or 4 minutes. Then steps 1-11 Avdi describes. In 5 browsers.

  3. One thing I love to do is use Selenium IDE as a macro recorder. When, for some reason, I cannot (or don’t want to) test-drive it, I speed the manual loop by just recording something, tweaking the selectors and then running it instead of doing it. Speeds up the preview->change->preview dramatically.

    This probably applies to a different set of problems, but I though I should share it anyway.

  4. I really like your approach, thanks for sharing. 

    This aspect of development doesn’t get the attention it deserves, and I think there’s a real problem here that needs to be solved. In my opinion, the problem is that the presentation code (HTML) and logic is in one place: the view. If those two things were separated, this would be a trivial problem to solve; just turn off the view logic and the only thing left is the static presentation code.

    You might be interested in checking out Pakyow (pakyow.com), which attempts to solve this problem by separating view logic from the view. I’d certainly be interested in hearing more of your thoughts on this topic.

  5. I find most view tweaks tend to be CSS, meaning that using Firebug in addition to a CSS reloader like ReCSS (http://david.dojotoolkit.org/recss.html) or ReSass (http://pivotallabs.com/users/david/blog/articles/1275-sass-development-at-the-speed-of-javascript) works well. Sure, there’s the occasional reload for actual HTML changes, but often that’s only if you’re trying to work around a layout problem where semantic markup doesn’t quite work. For extra speed you can bind your CSS bookmarklet to a hotkey. 

Leave a Reply

Your email address will not be published. Required fields are marked *