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}"
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

“Did you do anything to the colors in this one?”
The De-saturation

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

“Did you do anything to the colors in this one?”
Alternatives
Here are some alternative things to say:
- “I like it, How you made it look like this?”
- “Wow, how did you know that color treatment would be so cool?”
- “Why don't more people finish pictures like that?”
- “Can I pay for you and your family to accompany me on a lavish vacation to [ Europe | Japan | China | Mexico | Argentina | Moscow ] so you can take pictures for us?”
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
- Be specific
- Be direct and to the point
- Be courteous but avoid too many pleasantries
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:
- Your message is urgent
- Your message is brief
- You expect your request will not take an extended period of time to fulfil
- Your message does not require followup
Reasons to use email:
- Your message is intended for more than one individual
- You wish to CC the individual's superior to ensure proper priority is set to your request
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",'
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.
- Wrap the delete link in a div or span in order to make some space between the recipe name and the word delete.
- Add an "edit" link to the list for quickly arriving to the edit screen. You should use a "cookbook_recipe_path" method.
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:
- Add the recipe to the list
- Clear the form
- 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:
By dancing in an uncool fashion - sharp objects will be hurled at you
Please Do Not Shoot The Campers
