Tuesday, April 29, 2008

Show Hidden Fields Plugin

Unhide hidden fields during Rails development. Unhidden fields reveal themselves in grayscale to suggest their unhidden-ness. Onmouseover they'll also display their name & id.

All is revealed... Rails authenticity tokens, the REST put-method work around, etc - along with our own sleight of hand hidden stuff. Also makes so you can easily change unhidden field values, since they are now just text fields.

Hiding can be switched on/off by setting SHOW_HIDDEN_FIELDS = true/false. Handy for us devigner types who still like to make sense of stuff from the view! (-;

To install:

  1. Public clone url git://github.com/leewbutler/show_hidden_fields.git
  2. In config/environment.rb's init block add SHOW_HIDDEN_FIELDS=true
  3. Restart your server environment.

Wednesday, April 23, 2008

Kick Starting A Rails Application

I recently got started on a new rails pet project. When working on your own project you wear all the hats, call all the shots, and do all the work - for better or for worse. No matter where it falls in the end, you learn so much in the process.

In that spirit, my goal is to treat this project like my own personal startup weekend session, with a focus on momentum and forward motion.

Working Toward A Frankenstein - Mocking Up My Models & UI

To move my idea from vapor-ware to Frankenstein in good time I start right in by sketching out a quick and dirty mockup of the Models needed to get the gears turning. After a little pencil chewing and eraser dust I've got something rough to work with. My next step, since I'm historically a UI developer, is to throw together a basic clickable wireframe to compliment my rough Model sketch.

I am truly just going for a Frankenstein at this point - exposed stitches and bolts and all. Lets get this beast lurching forward.

For the mockup I use the haml driven staticmatic (highly recommend for mockups) and all goes quickly. Nice! It's like hoisting a lightning rod...and the beast begins to stir.

Refactoring My Frankenstein - Employing Imaginary Business Logic

I've skipped mocking up the obvious form pages but I do make a point to create Views for the areas of functionality that are not standard, or at least not plainly familiar to me. For instance I have an image Model that I want the user to be able to crop and size. Since I've never built an online image cropper I decided to mock it up and see what kind of question marks I encounter in the process.

With my plain-jane-greyscale UI in place I click through my pages to imagine the business logic I'll need to make my Views and Models work together. During the click-through process I continue to redefine my Models with needed attributes id's of other related Models. Sticky parts rear their ugly head but since I have no business logic written yet, changing the Models & Views is simple. Common patterns come to light and two Models get abstracted into one, etc. The more back and forth I do, the more simple and clearly defined my solution becomes.

Likewise, my Views mature as I whittle them down to exactly what needs to be displayed and gathered to support both my imagined business logic as well as my imagined end user expectations.

At this stage, my Model mockups now take on a less sketchy format so I can easily converted them to a script/generate rspec_scaffold later:

  Pirate
    name:string
    is_one_eyed:bool
  
  PirateType
    name:string
  
  Jewel
    name:string
    description:text
    is_cursed:bool
  
  JewelsPirates
    pirate_id:integer
    jewel_id:integer

Teasing Out Enums and States

As I continue to refine my Models, there are two types I keep a special look out for. First I take note of all the enumerations I run into. These are the Models that usually show up in drop down lists, that only have a name and id, and that lend themselves to a naming convention of xyz_type.

I like to manage all my enumerations from one place using Trevor Squire's acts as enumerated plugin. With that in mind, when I find an enumeration I write down all the values it needs to contain.

The second Model type I look for is any Model that uses (or could use) state. For example, if I notice a Model has many boolean attributes (is_reviewed, is_archived) that could be better represented by a single string attribute called "state" (state = pending_review, reviewed, archived) then I'll swap in the single "state" attribute for the booleans and write down the states the Model can be in. Later I will apply Scot Barron's excellent acts_as_state_machine plugin to manage those states.

Initial Migrations

So I've teased out my Enumerations, States and a number of additional Models. Excellent. Now my Model mockups look something like this.

  Pirate
    name:string
    is_one_eyed:boolean
  
  PirateType
    name:string
  # PIRATETYPES = good, bad, undead
  
  Jewel
    name:string 
    description:text
    state:string 
  # JEWEL STATES = un_stolen, stolen, cursed, buried
  
  JewelsPirates
    pirate_id:integer
    jewel_id:integer

Before I start generating database migrations, I write two initializer migrations by hand.

  001_create_initial_enums
  002_create_initial_joins

The "enums" migration creates all my enum Model tables and writes the values I've noted to the database. The "joins" migration creates all my join tables, sans any id attribute.

Generating The Beginnings Of My Rails App

Now I'm ready to dive forward and turn my mockups into a living Rails App. With the shorthand I've used for my Model mockups I can easily create a series of script/generate calls...

  
    script/generate rspec_scaffold Pirate name:string is_one_eyed:boolean
    script/generate rspec_scaffold Jewel name:string description:text state:string
  

Ahh, generators...it's like having a hindu god in your pocket. But the form Views getting generated are not even close to something I'll use for my actual forms. I know, I know - the scaffold Views are repudiated for only being there to impress clients and the uninitiated, but because I have a pretty solid mockup and a clear idea of the hamlized html I'll be using for my forms, I may as well generate something I can work with. So before I start generating, I'm going to modify the default RubyOnRails scaffold templates in two ways:

  1. Make them generate .haml instead of .erb
  2. Make them layout my forms using an html <dl> list.

Check back soon if your interested. I'll continue documenting my process.

Friday, April 18, 2008

XDressed Clickables

"Dude, for a second I totally thought that link was a button!"

As a user interface developer I run into The Problem With Get Requests (Agile Web Development With Rails, pg397) when working in the interface realm of a rails project - often I want to use a link where the action, or :method it invokes suggests I should use a button.

But when wearing the UI designer hat, my goal is to make sure the user's interaction with the application is intuitive as possible. If a user expects some functionality to be represented by a link, or by a button, that's how I want to represent it.

Rails employs client side javascript to solve the issue of using a link where a button should be, but what if I don't want to depend on javascript and still want to match user expectations with a link. Or even visa versa? How can I, ahem, have the best of both worlds?

I put together some x-dresser classes for my buttons & links to parade around in. The two operative classes are link_as_button and button_as_link. As always the main challenge is getting things looking right on that brutal runway called IE, but with a modicum of styling you can get the look pretty near dead on; emulating a link underline in a button was the biggest challenge. If you interested in the solution, see the cross browser screen shots and css with explanatory comments below.

Adding/removing them is simple considering it's the footprint of a single stylesheet with two classes. Want to take them on a test run yourself? A little disclaimer: I have yet to use them in the wild but below I've outlined their usage, done some contextual tests, took some x browser screen shots of the tests, and have pasted the CSS styles used as of this writing. The CSS is well commented to let you know what's going on. For the latest code visit my git repository at http://github.com/leewbutler/xdressed_clickables, or git it now with...

 

        git clone git://github.com/leewbutler/xdressed_clickables.git
        

Usage

about x-dresser code
A normal button looks different in each browser. Maybe round or square, blue, etc... <input type="button">
Instead we'll use this button. It is styled to look the same in all browsers... <input type="button" class="button">
...this allows us to apply the same styles to make a link appear to be a button. link as button <a href="#" class="link-as-button"><a>
Likewise our links styles are defined to ensure x-browser consistency...
link <a href="#"><a>
...which allows us to make a button appear to be a link <input type="button" class="button-as-link">
...and a submit button too. <input type="submit" class="button-as-link">

Test Alignment Within Text

This line tests link as button the vertical alignment of our x-dressers link relative to the surrounding text. Looks great!

Test With The Button_to Helper

Lets also test x-dressing when applied to the RubyOnRails button_to helper. We'll perform the test amidst a crowd of actual links that are none the wiser.

Actual link that is none the wiser.
Actual link that is none the wiser.

Looking good girl! However the button_to that is x-dressing above would be outed if asked to appear inline instead. This is because the RubyOnRails button_to helper wraps the button in a <form> tag. The form tag forces a line break in the display, both above and below our button. But otherwise our button is looking just like your average everyday link!

Test Results On Major Browsers

xdressed_clickables.css

The styles here are only for reference (it might be outdated by the time you read this). If your looking for the latest stylesheet see the git instructions above.

    /* ------------------------ BEGIN: link-as-button ----------------------------- 

      Start by enforcing a consistent x-browser button style. To that end we are 
      styling three classes in one style definition: 1. button, 2. submit and 
      3. link-as-button. Here's some example usage...

      <input type='button' class='button' value='press me' />
      <input type='submit' class='submit' value='submit me' /> 
      <a href='someurl' class='link-as-button'>I look like a button!</a> */

      input.submit,
      input.button, 
      a.link-as-button, 
      a.link-as-button:hover, 
      a.link-as-button:visited {
          text-decoration: none;
          cursor: default;
          font: 12px arial;
          padding: 2px 3px;  
          color: #000; 
          background-color: #eee; 
          border-width: 2px;
          border-style: solid; 
          border-color: #ddd #888 #888 #ddd;
          /* correct ie padding and alignment */
          vertical-align: middle;
          width:auto;
          overflow:visible; 
      }

      /* Remove extra 1px pad browsers give <INPUT>s by applying exactly 
        1px less than our above styles for <A CLASS='link-as-button'> */
      input.submit, 
      input.button {
        padding: 1px 2px; 
      }

    /* ----------------------- END: link-as-button --------------------------- *



    /* ------------------------ BEGIN: button-as-link ------------------------ */

        /* Enforce a consistent x-browser link style.*/
        a { 
          font-size: inherit;
          font-family: inherit;
          color: #009; }

        a:hover { 
          color: #00f; } 

        /* Apply our link styles to a button */
        input.button-as-link {
         /* Remove buttonisms */
          border: none; 
          margin: 0px 1px;
          padding:0px;
          /* Add linkisms */
          font-size: inherit;
          font-family: inherit;
          color: #009;
          cursor:pointer; 
          /* Correct padding in ie */
          width:auto;
          overflow:visible; 
          /* The underline challenge:
                - There's no support for 'text-decoration: underline' in <inputs type='button'>.
                - Using 'border-bottom: 1px' proves to create vertical alignment issues in x-browser testing.
                - Using a bg image for the underline works great */
          background:transparent url(../images/underline_blue_009.gif) repeat-x scroll 1% 90%; 
        }

        input.button-as-link:hover {
          color: #00f;
          background:transparent url(../images/underline_blue_00f.gif) repeat-x scroll 1% 90%;
        }


        /* Apply 3 Filters to adjust the above styles in:
            1) SAFARI: pull the underline image up 5% more */
         html[xmlns*=""] body:last-child input.button-as-link, 
         html[xmlns*=""] body:last-child input.button-as-link:hover { 
            background-position: 1% 95%; 
          }

        /* 2) IE7: Adjust the font to match a text link, 
              and pull the underline up 10% more */
        *:first-child+html input.button-as-link, 
        *:first-child+html input.button-as-link:hover {
          background-position: 1% 85%;
          vertical-align: -10%;
          font-family: times;
          font-size: medium;
        }

        /* 3) IE6>: Repeat the above IE7 adjustments but use 
              the *html filter to target IE6 and under. */
        * html input.button-as-link, 
        * html input.button-as-link:hover {
          background-position: 1% 85%;
          vertical-align: -10%;
          font-family: times;
          font-size: medium;
        }

        /* Finally, we might not be able to make the rails <form class='button-to'> 
           display inline, but lets at least cut out any extra space it takes up. */
        form.button-to {
          padding: 0px;
          margin: 0px; 
        }

    /* ------------------------ END: button-as-link ------------------------ */

Thursday, April 17, 2008

Inputs With Class Plugin

A rails plugin for automating best practice form styling.

Ahhh. Flush with my first rails plugin. Feels good! Now it's time to see what releasing one in the wild is like...

Seems like a good occasion to thank all the reliable plugin producers out there who's work I've benefited from in the past. I hope my work might some day prove to be even partially as time saving and useful a contribution to your projects, as yours was to mine.

The following write up is from the plugin's README.

Quick Intro

  1. Rails generated <input/> tags automatically get classed for their ‘type’ value.
  2. Rails generated <select/> lists automatically get classed as ‘single’ or ‘multiple’.
  3. Avoid name conflicts with your existing css classes by adding an optional class name prefix.
  4. Generate a starter stylesheet with some crisp default styles.
  5. Plays nice with any ad-hoc helper classing you do.
  6. To get unclassy again just pass in :class => false
  7. 25 tests confirm functionality in all relevant rails helpers.

To jump down to a more detailed intro to each of the above features click here.

Install

  1. From your plugins directory.
    git clone git://github.com/leewbutler/inputs_with_class.git
    
  2. Add the css file to your public/stylesheets directory.
    rake inputs_with_class_css
    
  3. Call the stylesheet from the head of your erb template.
    <%= stylesheet_link_tag 'inputs_with_class.css' %>
    

Why

When a CSS developer wants to set the width of all form text fields to 200px, they might try this.

input { width: 200px; }

Unfortunately this not only makes all text inputs 200px, but also all radio buttons, checkboxes, etc, because all are represented by the same html tag <input/>. It makes perfect sense to your browser... "What? You told me to make all input tags 200px so that's EXACTLY what I did" but makes for horrible layout results. To solve the issue in modern browsers you can use attribute selectors.

input[type="text"]{ width: 200px; } 

input[type="radio"]{ width:  30px; }

Problem solved! Time to go do something super fun! But not so fast. )-: IE6 rears its ugly head and injects another fat dose of un in our fun with no support for attribute selectors. Instead the consensus among UI developers is to manually add a class named for the input-type of the form element - so you get the pattern...

<input type='text'  class='text' />
<input type='radio' class='radio'/>

It's a common practice that clutters rails helper calls with predictable classes. The inputs_with_class plugin automates this pattern along with two additional common class patterns to style our 'single' and 'multiple' select lists.

Detailed Intro

Inputs_with_class automatically applies best-practice (universal standard) css naming conventions to all rails generated form elements, thereby giving your css developer full style control of forms right out of the starting gates. Its functionality includes:

  1. Rails generated select lists automatically get classed as 'single' or 'multiple'.
    <select class='multiple' multiple='multiple' size='2' >
    <select class='single'>
    
  2. Rails generated <input/> tags automatically get classed for their 'type' value.
    <input class='password' type='password'/>
    <input class='checkbox' type='checkbox'/>
    <input class='button' type='button'/>
    <input class='hidden' type='hidden'/>
    <input class='submit' type='submit />
    <input class='image' type='image'/>
    <input class='radio' type='radio'/>
    <input class='file' type='file' />
    <input class='text' type='text'/>
    
  3. Avoid naming conflicts with your existing css classes by adding an optional INPUTS_WITH_CLASS_PREFIX in the config block of your apps config/environments.rb.
    INPUTS_WITH_CLASS_PREFIX = 'bacon-'
    

    Gets you this....

    <input type="text"  class="bacon-text" />
    <input type="radio" class="bacon-radio" />
    
  4. Generate a starter stylesheet with all related classes and some basic default styles. From the command line in your app root...
    rake inputs_with_class_css
    
  5. Plays nice with any ad-hoc helper classing you do, so you get...
    class="yourclass inputswithclassclass"
    
  6. When the time comes, and you suddenly decide to get unclassy again...
    :class => false
    
  7. 25 tests confirm functionality in all relevant rails helpers. From the command line in your app root...
    cd vendor/plugins/inputs_with_class
    rake test
    
  8. Heads up for these gotchas when you add or change your INPUTS_WITH_CLASS_PREFIX.
    1. The names in your stylesheet need to be manually changed to match.
    2. The server needs to be restarted for the prefix to register.
  9. Future dev goals:
    1. Apply the pattern within the haml engine (if present) to automatically style any hand coded %input and %select tags. Git branches toward this goal are welcome. (-: