Amazon SQS in Ruby

June 16th, 2008

Use RightScale’s AWS ruby library it uses the newer version of the AWS WSDL. To install the gem:

$ sudo gem install right_aws

Here is some example code:

require 'rubygems'
require 'right_aws'

sqs = RightAws::SqsGen2.new('secret','secret key')
#create queue if it does not exist:
q = sqs.queue('my_awesome_queue',:create=>true)

puts "queue url: #{q.url}"
puts "Queue name: #{q.name}"

q.send_message 'This is a message!'

m = q.pop

puts "Message received:"
puts m.body
puts "id: #{m.id}"

The right_aws documentation.

0 comments »

Color Dr.

June 8th, 2008

“Did you doctor the colors of this one?” seems to be a common question for my photography. I've started to adopt answers like “of course: every single one” or “a photo isn't complete until after I’ve ‘messed with it’”

I'm sure I'm wrong but when I hear that question what I hear is “You aren’t a real photographer— you could not have made that image. A computer must have made it for you.” It's annoying.

The people who ask these questions are probably just trying to be conversational so I take all the blame for the what I hear but it is still there.

There are several scenarios where this question is asked...

The color toning

green picture

“Did you do anything to the colors in this one?”

The De-saturation

wedding photo with funny colors

“Did you do anything to the colors in this one?”

The Painfully Obvious

wedding photo with funny colors

“Did you do anything to the colors in this one?”

Alternatives

Here are some alternative things to say:

Spare Change?

June 8th, 2008

I was walking to lunch with some co-workers today and I was in the middle of some kind of a rant when someone from a bench says "Any spare change?"

I didn't have any so I meant to say "No, sorry." Instead what I said was "No Thanks!"

Casey said, "I think he was asking, not offering."

It was funny.

I am very grateful for the many ways my life has been blessed. I don't really know how to help homelessness but I donate to charitable organizations and although I don't know if it helps or hurts I do try to give change away if I have it on me.

It was just a funny accident and we thought of other things that would be funny (in a wrong way) to say:

"Spare change?"
"No, thank you: I've got way more than I need."

"Spare Change?"
"Maybe... I need a Vermont state quarter for my collection, do you have one?" --Amy

"Spare change?"
"No way, I don't want that stuff weighing me down!"

IM Etiquette

June 8th, 2008

We use Instant Messaging at my job. I don't like how some people use it and I wrote this guide a few years ago. As I re-read it today I realize that my feelings aren't quite as strong as they used to be.

General Guidelines for Business IM

When to IM & When to Email, When to Call

IM can be a great tool for communicating. It can also be the WRONG tool. Here are a list of reasons to use instant messaging:

Reasons to use email:

Initiating a Conversation

When initiating a conversation it's best to lead off with what you are contacting the other party for:

Frank: Hey Jane, could you check the fax machine to see if I got a fax?  
       It's hard for me to make it up the stairs since I broke my ankle.
Jane: Sure, just a sec
Jane: Nope, no fax yet
Frank: Darn. Maybe that African Prince email was a scam after all.  Thanks anyway.

Another good example is the following:

(8:32:22)  Jane: Hey Frank, let me know when you are back at your desk, I have a fax to drop by
(10:15:11) Frank: I'm back Jane- that meeting was murder.

Here is an example of what not to do:

(8:12:22) Bill: Hey Ted!
              (meanwhile Ted sees the message but is very busy on something 
               and decides to wait to see if Bill wants anything)
(8:17:51) Bill: Hello? You there?
(8:17:52) Ted: Yes, I'm here. Do you need something?
(8:19:43) Bill: Oh, cool. I thought you weren't around because you didn't answer.
(8:22:23) Bill: So.. hey, could you like do me a favor?
                (meanwhile Ted waits to see what Bill might need)
(8:27:01) Bill: Ted! BUZZ! Hey did you go?
(8:27:35) Ted: No. What do you need?
(8:28:17) Bill: Ok, good because you didn't respond and I didn't know what happened.  
                Can you check the report, I think their might be an error on it.
(8:29:45) Ted: What report are you talking about?

You get the point. Because Bill didn't specify his needs clearly and quickly Bill and Ted's adventure cost Ted 4 interruptions and about 20 minutes of time that they won't be able to get back.

Yeah, Yay, Ye, Yea, & Ya

June 4th, 2008

These are all different words with different meanings.

Yeah as in "Oh Yeah! I fogot about that." is a derivitive of the word "Yes." Meaning affirmative or to state you are in agreeance.

Yay as in "Yay! We get to eat cake today." is an exclamation of joy or delight. Use it when good news has just been shared with you.

Ye as in "Ye are a lost people" used originally only as a plural pronoun of the second person in the subjective case and now used especially in ecclesiastical or literary language and in various English dialects.

Yea as in "Yea, verily, I say unto you" (pronounced the same as "Yay") -- more than this : not only so but -- used to introduce a more explicit or emphatic phrase. Also used in oral voting "All in favor?" "Yea"

Ya this is a common mispelling of the word "Yeah." It is not an acceptable substitute. Just type the whole word.

Lines

June 4th, 2008

I really don't like lines. Even in a time where it seems half of all conversations mention gas prices. I don't hesitate patronizing the more expensive station if I see there is a wait at the cheaper one. gasp Yes, I'll pay 3 or 4 cents more PER GALLON to fill up my 13 gallon tank. I know this adds up: $0.52 per fill up. That's like $30/year! I'm fortunate in that I don't drive an SUV and I live close to where I work (and I usually get a ride).

Caching S3 Objects

May 22nd, 2008

So I just deployed a new version of Spokt.com with the static content hosted by the Amazon S3. I underestimated the number of requests that would be generated and found a way to reduce it with caching. I hope it works.

require 'rubygems'
require 'aws/s3'

AWS::S3::Base.establish_connection!(
:access_key_id => 'access id not shown',
:secret_access_key => 'secret key not shown'
)

photos = AWS::S3::Bucket.find('media.spokt.us',:prefix=>'images/')

puts "#{photos.size} files found."

photos.each do |photo|
    puts "updating #{photo.key}..."
    photo.cache_control = 'max-age=315360000'
    photo.save({:access => :public_read})
end

To ensure the cache-control header was added I ran a curl command to get the headers:

$ curl -I http://media.spokt.us/images/contentBoxHeader_04.jpg

HTTP/1.1 200 OK
x-amz-id-2: kEPTZ1ZdNo2nGsUnel5wDwsGi1pXTrkk6XGtSKKzb7zZguJjIwpaUCoUgESYbzkA
x-amz-request-id: 5DD73A7EEB692C0D
Date: Fri, 23 May 2008 05:09:53 GMT
x-amz-meta-s3fox-filesize: 322
x-amz-meta-s3fox-modifiedtime: 1183963918000
Cache-Control: max-age=315360000
Last-Modified: Fri, 23 May 2008 05:05:16 GMT
ETag: "1db8a1d3cb59acda667de962516c3cef"
Content-Type: image/jpeg
Content-Length: 322
Server: AmazonS3

There it is... now we'll see if we see fewer GET requests tomorrow.

Small Caps in CSS

May 20th, 2008

I created a quick webiste mock up last night... I wish I were a designer :)

I created the mock up in photoshop then copied the design to HTML + CSS. Photoshop has a feature that makes all letters upper case with the truly capitalized ones bigger and the lower case letters smaller. I found that CSS allows for this same behavior.

Regular: The United States of America

Small caps: The United States of America

Here is a css class definition for small caps:

font-variant:small-caps;

SCP Secure Copy

May 20th, 2008

So, I'm late to the Linux party. Today I learned how to use ‘scp’ to securely copy files between servers. Very late to the party. From my macbook pro I type this command:

 scp dhixon@communicatopia.com:backups/ctopia.sql ctopia.sql

Scp establishes an ssh connection with communicatopia.com and grabs the communicatopia.sql file from the backups folder in my home directory and copies it to the current working directory on my apple. It is terribly easy. For my next trick I want to configure a cron job to run a ruby script to mysqldump every night then upload it to my S3 account.

0 comments »

Rails Lesson #6: More Ajax

May 12th, 2008

In this lesson we'll see how partials work and we'll add a few more ajax niceties.

Partials are just .html.erb files that are useful for reusing “view” (as in Model-View-Controller) elements. They are easy to make and use - just add a ".html.erb" file to your view directory that starts with an underscore then call the render_partial method. Let's make one for our recipe list items.

Create a new file "_recipe_list_item.html.erb" in the "app/views/recipes" folder. This is the contents of the new file:

<% recipe = recipe_list_item[:recipe] %>

<li id="recipe_<%= recipe.id %>">
    <%= link_to(recipe.name, cookbook_recipe_path(@cookbook,recipe))  %>
</li>

This grabs a recipe out of the rails-built hash and then renders a list item with a link to the recipe. Now we need to change our app/views/cookbooks/show.html.erb to use this partial.

Change this:

<ul id="recipe_list">
<% @cookbook.recipes.each do |recipe| %>
    <li>
        <%= link_to recipe.name, cookbook_recipe_path(@cookbook,recipe) %>
    </li>
<% end %>
</ul>

To this:

<ul id="recipe_list">
<% @cookbook.recipes.each do |recipe| %>
    <%= render_partial "/recipes/recipe_list_item",:recipe => recipe %>
<% end %>
</ul>

Go ahead and bring up a cookbook in your browser to ensure that nothing looks different. Now we need to change the create.rjs file that we made in the previous lesson to use this partial. In the last lesson I referred to the HTML in this file as "unsightly" because HTML doesn't belong in an rjs file. I suppose there may be reasons for putting HTML in there but avoid it.

So, go ahead and replace this:

page.insert_html :bottom, "recipe_list",'
  • ' + link_to(@recipe.name, cookbook_recipe_path(@cookbook,@recipe)) + '
  • '

    with this that calls render_partial instead:

    page.insert_html :bottom, "recipe_list",:partial=>'recipe_list_item',:object=>{:recipe=>@recipe}
    

    While you have it open go ahead and add this line in there:

    page["recipe_" + @recipe.id.to_s].highlight
    

    Okay - now go ahead and reload your cookbooks page, then add a recipe. It works the same (only better because it highlights the new recipe after you add it!)

    The only thing left to do now is make it so we can delete the recipes from our list– you probably added a bunch of terrible recipes to your cookbook. I know I did: "Strawberry Hashmelt", "Boiled Beets", "flashy flashy", and of course: "sammy davis jr." Nobody is going to want these recipes so we need a way to delete them.

    Open up the recipelistitem partial and add a "remote" delete link:

    <% recipe = recipe_list_item[:recipe] %>
    
    <li id="recipe_<%= recipe.id %>">
        <%= link_to(recipe.name, cookbook_recipe_path(@cookbook,recipe))  %>
        <%= link_to_remote "delete", 
                :url => cookbook_recipe_path(@cookbook,recipe), 
                :confirm => 'Are you sure?', 
                :method => :delete %>
    </li>
    

    Because we are using a partial for the main display as well as the AJAX adds we didn't have to add that code twice: hooray!

    The linkto_remote tag will send a javascript request to the server. When the server receives a request via javascript we want to respond to it correctly. Open up your recipes controller and add a js format to the respondto block of the destroy action. Now just like we did for the create action we need to create an rjs file to define the behavior. The app/views/recipes/destroy.rjs file is very simple:

    page["recipe_" + params[:id]].hide
    flash.discard
    

    Go ahead and delete some of your lesser recipes.

    On your own

    Below are some tasks you should try to do on your own. I'll include my code for these next lesson when we get introduced to validations in rails.

    Rails Lesson #5: Ajax

    May 5th, 2008

    Today we want to change our application so we can add recipes to our cookbook right from the cookbooks/show page. First we'll do it without AJAX (asynchronous javascript and XML) then we'll add it in.

    Let's copy the new recipe form from app/views/recipes/new.html.erb and paste it into app/views/cookbooks/show.html.erb so that it looks like the code below. I also passed another parameter to the f.text_area methods (:rows=>5) because those text areas were just too tall.

    <%= error_messages_for :recipe %>
    
    <h2>Cookbook: <%=h @cookbook.title %></h2>
    <p>
      <b>Author:</b>
      <%=h @cookbook.author %>
    </p>
    
    <h3>Recipes:</h3>
    <ul>
    <% @cookbook.recipes.each do |recipe| %>
    	<li><%= link_to recipe.name, cookbook_recipe_path(@cookbook,recipe) %></li>
    <% end %>
    </ul>
    <br />
    <%= link_to "Add new recipe", new_cookbook_recipe_path(@cookbook) %>
    
    <!-- =========== BEGIN Form for new recipes =============  -->
    <!-- =========== BEGIN Form for new recipes =============  -->
    
    <%= error_messages_for :recipe %>
    
    <% form_for([@cookbook,@recipe]) do |f| %>
      <p>
        <b>Name</b><br />
        <%= f.text_field :name %>
      </p>
    
      <p>
        <b>Ingredients</b><br />
        <%= f.text_area :ingredients,:rows=>5 %>
      </p>
    
      <p>
        <b>Description</b><br />
        <%= f.text_area :description,:rows=>5 %>
      </p>
    
      <p>
        <b>Number of servings</b><br />
        <%= f.text_field :number_of_servings %>
      </p>
    
      <p>
        <%= f.submit "Create" %>
      </p>
    <% end %>
    <!-- =============== END Form for new recipes ==================  -->
    <!-- =============== END Form for new recipes ==================  -->
    
    <hr style="margin-top:25px;"/>
    
    <%= link_to 'Edit', edit_cookbook_path(@cookbook) %> |
    <%= link_to 'List', cookbooks_path %>
    
    <% end %>
    

    Notice the form_for passes an array containing @cookbook and a @recipe. We need to instanciate @recipe. That code belongs in the cookbooks controller:

    
      def show
        @cookbook = Cookbook.find(params[:id])
        #instanciate @recipe for the form
        @recipe = Recipe.new
        
        respond_to do |format|
          format.html # show.html.erb
          format.xml  { render :xml => @cookbook }
        end
      end
    
    

    At this point you can go ahead and use the form to add a recipe to your cookbook. After you create the recipe it takes you to the recipe's show action. Let's change that to redirect us back to the cookbook page. This code is in the create action of the recipe's controller. Change the redirect to redirect_to([@cookbook,@recipe]) to redirect_to(@cookbook).

           format.html { redirect_to(@cookbook) }
    

    Now it basically behaves how we will want. We just need to sprinkle some Ajax magic. Rails makes it pretty easy to do. We'll just include some javascript libraries, change our form tag and then code in Ruby how we want our output.

    Add this line to your views/layouts/application.html.erb right under the style sheet tag:

    	<%= javascript_include_tag :defaults %>
    

    Now to make a form submit asynchronous we call the form_remote_for method instead of the form_for. So change views/cookbooks/show.html.erb:

    <!-- ============== BEGIN Form for new recipes ================  -->
    
    <%= error_messages_for :recipe %>
    
    <% form_remote_for([@cookbook,@recipe]) do |f| %>
    
      ...
    

    If we were to fill out the form and click submit at this point it would look as though nothing happened but it would actually send a request to the server to the recipes controller's create method and create a record in the database. That was easy, right? Now all we have to do is send an XML response back to the client.

    Remember that “respond_to do |format|” block we saw a few lessons ago? We can represent our models as xml as well as html. This time we need to respond to a javascript request. Add “format.js {}” to your create action so that it looks like the following:

    respond_to do |format|
          if @recipe.save
            flash[:notice] = 'Recipe was successfully created.'
            format.html { redirect_to(@cookbook) }
            format.js   #this will use views/recipes/create.rjs
            format.xml  { render :xml => @recipe, :status => :created, :location => @recipe }
          else
            format.html { render :action => "new" }
            format.xml  { render :xml => @recipe.errors, :status => :unprocessable_entity }
          end
    

    As you can see from the comment when rails sees the format.js it will look for an rjs file named views/model/action.rjs. RJS stands for Rails JavaScript (might be "Ruby" or "Remote"). In this case it will be views/recipes/create.rjs. Go ahead and create an empty create.rjs file.

    We want the web page to do the following once we click submit:

    1. Add the recipe to the list
    2. Clear the form
    3. Erase the flash message

    The RJS file will contain ruby code that will be translated into JavaScript by Rails. In order for us to add dynamic content like an item to the list we need to give the containing HTML element an id. The ul tag in this case (cookbooks/show.html.erb):

    <ul id="recipe_list">
    <% @cookbook.recipes.each do |recipe| %>
    	<li><%= link_to recipe.name, cookbook_recipe_path(@cookbook,recipe) %></li>
    <% end %>
    </ul>
    

    Now for the rjs file. We'll clean this up a little bit in the next lesson but here is the contents of the create.rjs file which will take care of items 1-3 above in that order:

    page.insert_html :bottom, "recipe_list",'<li>' + link_to(@recipe.name,cookbook_recipe_path(@cookbook,@recipe)) + '</li>'
    page["new_recipe"].reset
    flash.discard
    
    

    First we use the insert_html method to add a list item to the "bottom" of the "recipe_list". Then we reset the "new_recipe" form and then call flash.discard to erase the flash message. Next time we'll get rid of that unsightly HTML in the create.rjs file by putting the list item into a partial as well as make it possible to delete recipes from cookbooks.

    More is Less

    May 4th, 2008

    Google Video: The Paradox of Choice why More is Less: http://video.google.com/videoplay?docid=6127548813950043200

    This lecture has given me a vocabulary and "evidences" to support my belief that software should be simple and offer fewer features. I feel that is where spokt.com varies philosophically from myfamily.com. We concentrate on making our features more powerful and easier to use instead of adding features.

    MD5 Hash in Ruby

    April 30th, 2008

    The top three google links I got for this seemed to require a lot of junk I didn't think I needed. I kept searching and found that it is exactly as ridiculously simple as I have come to expect from Ruby:

    require 'md5'
    puts Digest::MD5.hexdigest("This is what I want to hash")
    

    Sorry Signal

    April 29th, 2008

    I wish automobiles were more expressive. For one I wish there was a "nice" honk. When I'm behind someone who doesn't notice that the light turned green I'm not mad and I don't want to do a full "HONK." I'm sure that person wants to move forward just as much as I do but he or she happens to be distracted at the moment. Big deal. A little honk that says "Hey, the light is green, let's celebrate together and step on the gas" would be a welcome addition to automobiles and driving culture.

    I also long for a "I'm sorry" signal. I'm not a perfect driver and when I make a mistake I'd like to be able to acknowledge it to the drivers I affect. I think a flashing dunce cap would be a nice way to diffuse some road rage... or maybe the pinky finger out the window (it's the smallest most humble finger).

    Stick Figures in Peril

    April 27th, 2008

    I don't spend much time on Flickr however this pool kept me laughing:Stick Figures in Peril

    Some of my favorites:

    Electrical Hazard

    By dancing in an uncool fashion - sharp objects will be hurled at you

    Please Do Not Shoot The Campers

    Evil electricity could shoot a small child

    One I took in England: danger of death