Oomoo

August 20, 2008

How Do I ‘Refresh’ Individual Form Fields?

Filed under: ajax, controller, forms, model, rails, view — oomoo @ 11:13 pm

Recently, I wrote about creating a Ruby on Rails app that would create HTML formatted signatures for Outlook and web-based e-mail systems  (see: Outlook and the Double-Spaced Signature ).  This small application was my first chance to do true data-based entry using form fields (most of my prior RoR projects just tapped into existing databases for searching and presentation in a browser).

Well, most of my software development background has focused primarily on creating data-based applications with heavy data-entry and reporting, so I was eager to see if Rails was up to the task.  I used the Scaffolding classes built into Rails 2.1x to initially generate the pages (see, I wanted to call them screens or forms) to do the CRUD work, then I set about understanding how they worked and editing them to look a little better.

I understand the whole “disconnected” “stateless” model of web development, but I never dreamed it would be this dang hard to put a drop-down box and a couple of text fields inside form tags on a page and get them to interact with my database and with each other.  Of course, now that I know how to do it, it seems simple (and Rails is great again, the web makes sense, and all is right with the world).  Of course, what I could have finished in VFP in about 60 seconds took me many frustrating hours with more than one Rails/Ajax book thrown across the room.

For this application, I only have 2 tables (told you it was simple); Locations and Signatures.  The “Locations” table is a lookup table containing information that will be related to multiple “Signatures” (usually one Signature per person).

Locations Table:Locations schema

Signatures Table:Signatures schema

 

 

 

 

 

 

 

 

 

Locations.id  — Relates to —>> Signatures.location_id

Since each Signature relates back to a Location, if the Company changes their logo or web site, no change to the Signature record is needed, you need only regenerate the HTML signature for Outlook.  Okay, enough “database theory 101”.

Here is what I wanted to accomplish:

captured_Image.png Display a page where the user could select their “Location” from a drop-down combo field…

 

 

 

…once selected, the data from the “Location” phone/fax fields would automatically populate the first two phone fields of the “Signature” record. SigAfterLocation

…the phone fields would temporarily “highlight” to indicate to the user that something had changed

…then the fields would go back to their normal color, still containing the updated data from the Location record.

captured_Image.png[4]

 

 

 

 

Finally, the user “Saves” their Signature, and clicks the “Create My Signature” link which generates/downloads the HTML file containing their nicely formatted Outlook Signature.

captured_Image.png[6]

 

Piece-O-Cake!!!  No really, I wrote a complete version of this page using my desktop development tool (VFP) and it took me almost no time to have all the logic working and I even had a browser preview of the finished HTML that updated itself as you updated your signature.   Here is a screenshot of my desktop form written in VFP…

captured_Image.png[29]

 

We need our page to contain:

  • A Form (form_for)
  • A Drop-Down List (collection_select)
  • Some Labels (form.label)
  • Some Fields (form.field)
  • A Submit Button (form.submit)
  • Some way to know when a selection has been made from the drop-down list
  • Some way of updating the page based on the drop-down selection

 

    <% form_for @signature do |f| %>
    <div id="cbo_location_id", style="height: 31px">
        <%= f.label :choose_location, "Choose Your Location:",
                    :style => "top: 5px; left: 3px; position: relative; color: white; font-weight: bolder;" %>

        <%= collection_select("signature", "location_id", @locations, "id", "loc_name",
                              options ={:prompt => "...Select A Location",
                              :include_blank => false},
                              html_options={:style => "top: 7px; left: 15px; position: relative;"}) %>

        <%= observe_field("signature_location_id",
                          :url => { :action => "location_lookup" },
                          :with => "'id=' + value") %>
    </div>
    ...other form fields here...

        <table width="350" height="150" cellpadding="0" cellspacing="0">
           <tbody> <tr> <th align="center"> <%= f.label :phone_desc, "Desc.", :style => "color: white;" %> </th>
                        <th align="center"> <%= f.label :phone_num, "Number", :style => "color: white;" %> </th></tr>
                   <tr> <td align="center"> <%= f.text_field :sig_p1_desc, :size => "10", :style => "" %>  </td>
                        <td align="center"> <%= f.text_field :sig_p1_num, :size => "20", :style => "" %>   </td></tr>
                   <tr> <td align="center"> <%= f.text_field :sig_p2_desc, :size => "10", :style => "" %>  </td>
                        <td align="center"> <%= f.text_field :sig_p2_num, :size => "20", :style => "" %>   </td></tr>
                   <tr> <td align="center"> <%= f.text_field :sig_p3_desc, :size => "10", :style => "" %>  </td>
                        <td align="center"> <%= f.text_field :sig_p3_num, :size => "20", :style => "" %>   </td></tr>
                   <tr> <td align="center"> <%= f.text_field :sig_p4_desc, :size => "10", :style => "" %>  </td>
                        <td align="center"> <%= f.text_field :sig_p4_num, :size => "20", :style => "" %>   </td></tr>
             </tbody>
          </table>

    <div style="height: 35px"> <p> <%= f.submit "&nbsp;Save&nbsp;" %>  </p>  </div>
  <% end %>

 

We need our form to:

  • Know that a selection has been made from the drop-down list:

       ( \app\views\signatures\edit.html.erb )

    <%= observe_field("signature_location_id",
                       :url => { :action => "location_lookup" },
                       :with => "'id=' + value") %>
  • Retrieve the chosen “Location” data:

      ( \app\controllers\signatures_controller.rb )

    class SignaturesController < ApplicationController
    
      def location_lookup
        @location = Location.find(params[:id])
      end
      ...other controller methods...
    end
  • Update/refresh the fields on the page that have changed, and highlight them: 
      ( \app\views\signatures\location_lookup.js.rjs )
    page[:signature_sig_p1_desc].value = 'p.'
    page[:signature_sig_p1_num].value = @location.loc_phone.strip
    page[:signature_sig_p2_desc].value = 'f.'
    page[:signature_sig_p2_num].value = @location.loc_fax.strip
    
    page.visual_effect :highlight, :signature_sig_p1_desc, :duration => 2
    page.visual_effect :highlight, :signature_sig_p1_num, :duration => 2
    page.visual_effect :highlight, :signature_sig_p2_desc, :duration => 2
    page.visual_effect :highlight, :signature_sig_p2_num, :duration => 2

 

So, what is happening here?

  1. My drop-down list is:

        <%= collection_select…  %>
  2. When it’s value is changed, my “field observer” gets fired:

       <%= observe_field…  %>
  3. It’s "action" is defined as:

        :url => { :action => "location_lookup" }  
    which means it is going to call the controller action/method named "location_lookup"
  4. As a parameter, it is going to pass the "id" of the Location chosen:

       :with => "’id=’ + value"
  5. The "location_lookup" action/method in the controller "finds" the passed in Location ID:

       @location = Location.find(params[:id])
  6. Then (by magic) rails renders the contents of the RJS file.

    Actually, Rails will always look for an RJS file to exist that is named the same as the controller action/method.
  7. The RJS file will first update the field values with the contents of the Location data:

        page[:signature_sig_p1_num].value = @location.loc_phone
  8. Then, the RJS file will temporarily "highlight" the changed fields:

       page.visual_effect :highlight, :signature_sig_p1_num, :duration => 2

 

*Note – we didn’t need to use an RJS file, we could have achieved the same thing by putting the RJS code directly in the "location_lookup" controller action/method:

def location_lookup
  @location = Location.find(params[:id])

  render :update do |page|
    page[:signature_sig_p1_desc].value = 'p.'
    page[:signature_sig_p1_num].value = @location.loc_phone.strip
    page[:signature_sig_p2_desc].value = 'f.'
    page[:signature_sig_p2_num].value = @location.loc_fax.strip

    page.visual_effect :highlight, :signature_sig_p1_desc, :duration => 2
    page.visual_effect :highlight, :signature_sig_p1_num, :duration => 2
    page.visual_effect :highlight, :signature_sig_p2_desc, :duration => 2
    page.visual_effect :highlight, :signature_sig_p2_num, :duration => 2
  end
end

I just prefer to use the RJS file to keep my controller clean of view-specific things, and if you just think that the RJS is taking the place of the View (html.erb) that would normally be rendered after a controller action/method, then it makes sense.

*Note: "page" is an automatic reference to the existing web page object (DOM) that Rails is exposing so we can monkey around with it.  Now, isn’t that nice!

Since RJS is basically just "Railsified" javascript (AJAX), you can do just about anything to the existing web page.  You can add things, hide things, change all the colors, change the words, enable/disable things, and even insert calls to new javascript functions (like links to services on other web sites).

 

In review, the process involved really isn’t that different from what I had to code in my desktop VFP application.  The biggest difference was knowing what form elements to use (and their syntax) then just understanding that the full logic is done in pieces that are spread out over several files (view, controller, RJS).  In the end, the secret sauce for updating my field display is AJAX, simplified by the Rails helpers.

Happy Field Refreshing!!  –Oomoo

 

—UPDATE ––

Do you want to DEMO this application in your browser right now?

Just go here:  Outlook Signature Application

This web-based application is a full-featured signature generator for Outlook.  You can use it to create your signature or just use it as an educational tool.  This application was completely written at (and is hosted on) Heroku!!

(hint:  If you enter your “Location” and “Signature” information, be sure to delete it before leaving the site)

In fact, you can download the full source code here:  Download Source Code

August 19, 2008

Outlook and the Double-Spaced Signature

Filed under: Microsoft, Windows, rails — oomoo @ 9:43 pm

BTW, if you are not a programmer trying to create signature files, and you are just using Outlook and want to avoid double-spaced lines, simply hold down the [Shift] key when pressing the [Enter] key at the end of each line in your signature.  The signature editor (Word) will insert a "soft return" instead of a "hard return" and your signature will be nicely single-spaced.  If you are a programmer, read on…

So, the other day I’m called upon to write a web-based (Ruby on Rails of course) app for a client.  This app takes an employee’s information and generates a standard "company approved" signature block that can be used in both Outlook and web-based mail like GMail (Google Mail)/Yahoo/etc.  No big deal, everyone just uses HTML these days right?  Even Microsoft finally relented and HTML formatted messages are even the default in Outlook 2007.  Woo-hoo!  Word as an e-mail editor is finally dead!  I can’t tell you how many hours I have spent changing the default e-mail editor in previous versions of Outlook on client’s machines.

Back to the web app… 

Step 1, I did my research and found out that Outlook stores it’s signatures in the folder: C:\Documents and Settings\<user name>\Application Data\Microsoft\Signatures\   If I have an HTML signature named "MyWorkSig", it is actually stored in the signatures folder as MyWordSig.htm (not .html).  If it were a text signature, it would be stored in the same folder and have the same name, but would have a .TXT file extension (MyWorkSig.txt).  If it were an RTF (rich text format) signature, it would be stored in the same folder and have the same name, but would have a .RTF file extension (MyWorkSig.rtf). 

Step 2, I learned that you should not use CSS styles, but should "in-line" CSS formatting, which is just "style" information embedded into my HTML tags. 

style="font-size: 9px; color: #000000; font-family: Tahoma,Arial"

I also learn that you shouldn’t use the "html", "head", or "body" tags, because you are not really creating a full HTML page, just a piece of a page.

<html> <body> ....  </body> </html>

 

Step 3, after MUCH trial-and-error, I learned that the advice given on most websites about creating Outlook-compatible HTML signatures will just make your signature look crappy or will get your mail deleted by anti-spam packages because of embedded pictures or deceptive URLs.

Most sites will tell you to wrap your signature in one of these HTML tags/elements:

<div>...</div>    <p>...</p>     <table>...</table>

Why?  Well, if you don’t wrap your text in some type of HTML tag/element, you won’t be able to specify the "Style" information I eluded to in "Step 2".  This means that you won’t be able to format your signature with fonts or colors and you won’t be able to control the spacing/layout.  In that case, you basically have a TEXT signature, not HTML.

So, what’s the problem with using these tags in my signature?  Well, if you like lots of double-spaced lines in your signature, then go ahead and use them.  If you are like me and you want the signature coming out of Outlook to look the same as the one coming out of any web-based messages you send, then the infamous double-spaced Outlook signature is a fiasco!

When you send a message through Outlook, and your HTML signature encounters any "divider" tags, it will insert a double-spaced line.  It makes sense in a Microsoft-sort-of-way when you consider that each of the tags I mentioned are literally followed by a "hard return".  But, in a the-way-things-really-work-sort-of-way it’s just fubar’d.

So, how do you add divider elements/tags to your HTML so you can add your "style" settings without getting double-spaced? 

<span>...</span>

That’s right my fry-end, the lowly "span" tag will allow you to divide your text, specify all the formatting you spammy heart desires, but avoids the double-spaced line from hell.  Try this signature on for size:

   1: <table style="font-family:Tahoma,Arial; font-size:9px;" cellspacing="0" cellpadding="0">
   2:   <tr>
   3:     <td style="vertical-align: top; text-align: left;">
   4:       <span style="font-size: 12px; font-weight: bold;">Mr. Knows Itall</span>
   5:       <span style="font-size: 11px;"><br />Level 30 Cleric</span>
   6:       <span style="font-size: 12px; font-weight: bold"><br />Global Masters LLC</span>
   7:       <span style="font-size: 11px;"><br />phone: (777)-888-9999 </span>
   8:     </td>
   9:   </tr>
  10: </table>

You could just save this in your Outlook signature path (name it something like…. MySignature.htm), then pull up your Outlook signature settings, and choose (the newly available) MySignature as your signature.  Send yourself a message and you will see that no double-spaced lines appear (except following the "Table" tag, but we will let that one slide).

*Note that I had to manually insert "br" tags where I wanted a "line break" to appear.

 

Now, here is a full-blown HTML signature that has multiple tables for indentation, but the double-spaced lines Outlook will insert are almost useful to the end result:

<table style="font-family: Tahoma,Arial; font-size: 9px; color: #000000;"
              cellspacing="0" cellpadding="0">
    <tr>
        <td>
        <table style="font-family: Tahoma,Arial; font-size: 8px; color: #000000;
                      vertical-align: top; text-align: left; white-space: nowrap;"
                      cellspacing="0" cellpadding="0">
            <tr>
                <th colspan="2" style="text-align: left">
                <img src="companyx_logo.jpg" alt="(CompanyX logo)"
                          width="254" height="46" style="border-style: none" /></th>
            </tr>
            <tr>
                <td style="font-size: 8px; width: 60px; white-space: nowrap;">
                </td>
                <td style="vertical-align: top; text-align: left;">
                <span style="font-size: 12px; font-weight: bold;">Johnny B. Good</span>
                <span style="font-size: 11px;"><br />I.T. Warlock</span>
                <span style="font-size: 6px;"> <br /> <br /></span>
                <span style="font-size: 12px; font-weight: bold">CompanyX, Inc.</span>
                <span style="font-size: 11px;"><br />1 Main Street</span>
                <span style="font-size: 11px;"><br />Hangemhigh, TX 666777</span>
                <span style="font-size: 11px;"><br />p. 123-456-7890 f. 098-765-4321 </span>
                <span style="font-size: 6px;"> <br /> <br /></span>
                <span style="font-size: 11px;">
                  <a href="http://www.companyx.com" title="www.Companyx.com">www.CompanyX.com</a>
                </span>
                <span style="font-size: 6px;"><br /><br /><br /></span>
                </td>
            </tr>
        </table>
        </td>
    </tr>
    <tr>
        <td colspan="2" style="font-family: Tahoma,Arial; font-size: 9px; color: #000000;">
        PLEASE NOTE: This message, may include privileged blah blah blah...
        </td>
    </tr>
</table>

*Note: You will need to specify your own logo JPG, and change the width/height accordingly.  I chose to put my logo on the company website, and pull it from there instead of embedding it into the message.  Your mileage may vary using either technique.

*You will certainly want to make use of the "alt=" option in your "img" link (if you use one).  If, for any reason, your logo graphic is not downloaded/visible in the message, the "alt=" text will be what your recipient sees instead.

Learning all of this….interesting stuff….the hard way took me the better part of an 8-hour day (I am sad to say).  Hopefully, I just gave you back a few hours with your family.  Now, go home and tell them Oomoo sent you!

 

—UPDATE ––

Do you want to learn more about creating your own Outlook Signature Application? 

See this post: Application Notes

 

Do you want to DEMO this application in your browser?

Just go here:  Outlook Signature Application

This web-based application is a full-featured signature generator for Outlook.  You can use it to create your signature or just use it as an educational tool.  This application was completely written at (and is hosted on) Heroku!!

(hint:  If you enter your “Location” and “Signature” information, be sure to delete it before leaving the site)

In fact, you can download the full source code here:  Download Source Code

Update Rails/Rake/Gems

Filed under: gems, rails, rake — oomoo @ 9:09 am

Keep your Rails/Rake/Gems up-to-date by running these commands:

Update the RubyGems system itself (required by Rails 2.0).
gem update –system

Update Rails-specific gems and installs any new components (specifically Active Resource).
gem install rails

Update Rake, the build tool used by Rails.
gem update rake

Update the Ruby bindings for the SQLite3 database.
gem update sqlite3-ruby
. 

For an existing project, also do this:

rake rails:update

…and edit the config/environment.rb file and set the correct GEM Version:

RAILS_GEM_VERSION = ‘2.1.0′ unless defined? RAILS_GEM_VERSION

You might want to make sure your migrations are up-to-date:

rake db:migrate
rake db:schema:dump

 

Check your GEM version:
gem –version

 

Downgrade/Rollback GEM
gem -v

 

List all the installed gems by typing:

gem list

. 

View the documentation for all the installed gems by typing:

gem server

To access the documentation, point your browser to http://localhost:8808/

This command starts a web server on port 8808 by default. 

You’ll see a list of the gems you have installed with a link to their RDoc documentation.

 

Install SQLite3:
gem install sqlite3-ruby

 

Force Rails to use MySQL (instead of the default SQLite3):

rails -d mysql myapp

 

Blog at WordPress.com.