May 25, 2009
Kat and I have traded in our bikes for better models, only a couple weeks after buying them. We both got really good deals from Performance Bike in Reston on the upgrades. The new bikes are 21- and 24- speed instead of 7-speed, have front shock absorbers, and higher quality shifters, gears, brakes, and other parts. The additional gears are essential for dealing with the long and steep hills on the Fairfax Parkway trail.
I also have a new iPhone, and downloaded a great free application that uses the GPS to record your bike rides and map them on Google Maps. Below shows the route that was recorded yesterday when Kat and I rode over 21 miles (round trip) to Leesburg and back on the W&OD trail. We kept our pace brisk, and it was a really good workout — almost 1,800 calories for me according to the bike computer. I’ve now ridden around 100 miles total, and Kat’s gone further since she’s done some biking trips while I’ve been at work. She’s been logging our efforts in an online document here.
W&OD from Rt. 28 to Leesburg and back
I also rode to work last Monday, which was a lot of fun, but logistically complicated (backpack full of clothes, shower at work, etc.). It took me about 40 minutes to get to work, vs. the usual 15-20 when driving. But adding in all the prep time and shower time at work makes it more like 60, so 3-4 times as long. I’ll probably do it occasionally, but I don’t think it’ll become my primary way of getting to work.
I’m really enjoying biking, and am glad that we decided to get bikes this year. There are a lot of bike trails in Virginia, so we’ll probably find a way to start exploring more of them.
Posted in biking
2 Comments »
April 25, 2009
Kat and I bought bicycles last weekend, and are hoping to use them to get outdoors a bit more than we usually do. So far it’s been quite fun, and we’re looking forward to exploring lots of the W&OD trail and other areas. I took off work Thursday and we had our first test-ride with Scott, going around 12 miles on the trail, from the Rt 28 / AOL entrance, to the LuckStone Quarry overlook and back. Of course we had to finish it off with a chocolate malt and food at Cheeburger Cheeburger!

Today we left the car in the garage and rode from the house to my office in Herndon. I’d been toying with the idea of biking to work occasionally, but Kathie had the good idea of trying it together during a weekend first. It was 7.1 miles each way, and surprisingly almost all of it was on residential roads, the Fairfax County Parkway Trail (really just a wide sidewalk along the parkway), and the W&OD. There’s also a short jaunt through the woods at the end of our street, a 100-yard path that saves 1.5 miles and eliminates “roads you’d be crazy to bike on” like Seneca Road, Georgetown Pike, and Rt. 7.
The last mile of the trip, on Van Buren St. was more of a challenge, since we had to choose between the sidewalk or the road with no shoulder. We tried both, and while the road was fine on a Saturday morning at 9am, I’m not sure if I want to do that during rush hour on a weekday. Fortunately the speed limit on the road is 25mph and it’s aggressively enforced (don’t speed in Herndon!). Bicycles are allowed on sidewalks in Virginia (yield to pedestrians) so I’ll have to try both. It was a fun morning, and we’re both looking forward to a lot more biking!
Posted in biking, food/wine, work
Leave a comment »
February 2, 2009
For a project I’m currently working on, I needed a way to upload several photos to attach to a “dog” model, and allow easy cropping of the photos. In Ruby on Rails, this turned out to be harder than I expected.
The main problems I encountered were:
- There are several attachment uploading plug-ins for Rails, like attachment_fu, Paperclip, or UploadColumn, with various features and complexities, but none had good references on handling multiple uploads associated with one model instance.
- To add multiple attachments to an object requires a separate model for attachments, associated with the main model via a has_many/belongs_to relationship. This isn’t hard if the model views are kept separate and RESTful (create a new dog, then add a photo, then add another photo, etc). That’s not a good user experience however — I want to be able to add a new dog, and upload many associated photos at the same time.
- It turns out that complex forms to handle multiple associated models is pretty tricky in Rails (but should get better with Rails 2.3, coming soon).
- I also wanted to let the user manually crop the photos after upload, to just select the dog’s face for example.
After several weekends of experimenting, reading lots of blogs and tutorials, and playing with various plug-ins, I finally have a working solution I’m pretty happy with. Here’s what I ended up doing:
- I’m using the Paperclip gem to handle the actual uploads. The main reason I chose this over other options was that Paperclip lets me easily create additional “styles” of an uploaded photo, like a small thumbnail, a page-sized version, etc.
- I’m using the attribute_fu plug-in to handle the multi-model forms so I can upload any number of images at the same time as a new dog is created.
- I’m using the jsCropperUI JavaScript library to let the user select an area to crop.
- Since Paperclip requires ImageMagick to do its resizing, I installed RMagick and use that for my cropping.
Getting started
I have two models: “Dog” and “Upload”. I started by calling my second model “Attachment”, but after running into problems, I learned that Paperclip uses that name internally and will not work correctly if you name your model “Attachment”.
$ rails dogs
$ cd dogs
$ script/plugin install git://github.com/giraffesoft/attribute_fu.git
$ script/generate model dog name:string
$ script/generate model upload description:string dog_id:integer \
photo_file_name:string photo_file_size:integer
$ script/generate controller dogs
$ script/generate controller uploads
Models
The Dog model just has a name for now. The Upload model will represent each uploaded photo. It has a description which the user can enter, a dog_id foreign key, and two attributes for Paperclip: a photo_file_name string and a photo_file_size integer. See the Paperclip documentation for more details on how these (and other) special attributes are used.
# models/dog.rb
class Dog < ActiveRecord::Base
has_many :uploads,
:attributes => true,
:discard_if => proc { |upload| upload.photo_file_size.nil? }
end
I updated the Dog model to have many uploads. The “:attributes” parameter is part of attribute_fu, and lets the Dog controller create associated models at the same time a new Dog is created. The “:discard_if” tells attribute_fu not to create an associated model if certain conditions are met — in this case, if there’s no file that was uploaded. This is needed because we may put many file upload fields in the “new Dog” form, but a user may only select one or two photos. In that case, all the blank form elements would be submitted too, and created as empty Upload instances.
#models/upload.rb
class Upload < ActiveRecord::Base
belongs_to :dog
has_attached_file :photo,
:styles => {
:thumb => ["100x100", :jpg],
:pagesize => ["500x400", :jpg],
},
:default_style => :pagesize
end
This Upload model belongs_to a dog, to match the has_many association above. “has_attached_file” is part of Paperclip, and the “photo” attribute must match the prefix of the database fields above (e.g. photo_file_name). Paperclip can automatically re-size photos and keep multiple versions, based on the “styles” hash. Here we create a small thumbnail, and a version good for embedding in web pages. In both cases, the photo is converted to a JPEG if needed. The original photo is stored with a style of “original”.
Views
The main view we’re concerned about is the “new dog” view. This will give the user a form to add a new dog, and upload photos to associate with the dog.
# views/dogs/new.html.erb
<h1>New dog</h1>
<% form_for @dog, :html => { :multipart => true } do |f| %>
<%= f.error_messages %>
<p>
<%= f.label :name %><br />
<%= f.text_field :name %>
</p>
<div id='uploads' style='border: 1px solid silver'>
<%= f.render_associated_form(@dog.uploads, :new => 5) %>
</div>
<%= f.add_associated_link('Add another photo', @dog.uploads.build) %>
<p>
<%= f.submit "Create" %>
</p>
<% end %>
The first part of the above view gives us a form for a new dog instance. It also calls attribute_fu’s “render_associated_form” to create a nested form for upload instances. Here we create five blank instance forms. The instance forms are generated by a partial named after the associated model… in this case the partial is _upload.html.erb (below). We also add a link to create additional file upload forms on the fly via attribute_fu JavaScript with the “add_associated_link” call.
# views/dogs/_upload.html.erb
<p class='upload'>
<label for="upload_description">Description:</label>
<%= f.text_field :description %>
<label for="upload_photo">Photo:</label>
<%= f.file_field :photo %>
<%= f.remove_link "remove" %>
</p>
The partial is pretty standard, just a field for our photo description, and a file upload field. The only unusual part is attribute_fu’s “remove_link” JavaScript call, which lets the user remove one of the photo upload forms.
Here’s what the completed form looks like:

Controllers
The nice thing about attribute_fu is that no special controller logic is needed! The dog controller is just a standard RESTful controller! When the form is submitted, the dog instance is created, and all the associated upload instances are created simultaneously:
# controllers/dogs_controller.rb
class DogsController < ApplicationController
def index
@dogs = Dog.find :all
end
def show
@dog = Dog.find params[:id]
end
def new
@dog = Dog.new
end
def create
@dog = Dog.new params[:dog]
if @dog.save
flash[:notice] = 'Dog was successfully created.'
redirect_to @dog
else
render :action => "new"
end
end
end
Image cropping
The last feature to add is the image cropping functionality. We’re going to do this in the “edit upload” action. The edit form will show the image, and let the user drag a rectangle around the region to crop. The form will return the rectangle coordinates, and we’ll override the standard update_attributes method of the Upload model, to perform the crop.
In the main view template, I’m including the jsCropperUI JavaScript code and its dependencies. The scripts go in the public/javascripts directory when you install the jsCropperUI code.
# views/layouts/application.html.erb
<%= javascript_include_tag 'cropper/lib/prototype.js' %>
<%= javascript_include_tag 'cropper/lib/scriptaculous.js?load=builder,dragdrop' %>
<%= javascript_include_tag 'cropper/cropper.js' %>
The “edit upload” view is a little complex. Here’s how it’s put together:
# view/uploads/edit.html.erb
<h1>Editing upload</h1>
<% form_for(@upload) do |f| %>
<%= f.error_messages %>
<p>
<%= f.label :description %><br />
<%= f.text_field :description %>
</p>
<!-- CROP FORM -->
<div id='cropwrap'>
<%= image_tag @upload.photo.url, :id => 'cropimage' %>
</div>
<div id='cropresults'>
<%= f.label 'x1' %>
<%= f.text_field 'x1', :size => 6 %>
<br />
<%= f.label 'y1' %>
<%= f.text_field 'y1', :size => 6 %>
<br />
<%= f.label 'width' %>
<%= f.text_field 'width', :size => 6 %>
<br />
<%= f.label 'height' %>
<%= f.text_field 'height', :size => 6 %>
<br />
</div> <!-- cropresults -->
<!-- END CROP FORM -->
<p>
<%= f.submit "Update" %>
</p>
<% end %>
In addition to the edit field for our model’s normal attributes (”description”, in this case), we also have fields for the geometry of our crop rectangle. These fields will be filled in automatically by the jsCropperUI. We also need to display the image we’re cropping, and identify it with a CSS ID so the jsCropperUI can attach to it. To attach the jsCropperUI, we need to add some JavaScript to the page:
# view/uploads/edit.html.erb
<script type="text/javascript" language="JavaScript">
function onEndCrop( coords, dimensions ) {
$( 'upload_x1' ).value = coords.x1;
$( 'upload_y1' ).value = coords.y1;
$( 'upload_width' ).value = dimensions.width;
$( 'upload_height' ).value = dimensions.height;
}
Event.observe( window, 'load', function() {
new Cropper.Img('cropimage', {
minWidth: 50,
minHeight: 50,
displayOnInit: true,
onEndCrop: onEndCrop
} );
} );
</script>
This attaches the jsCropperUI to the photo we want to edit, identified by the “cropimage” CSS ID. It also sets up a callback function to set our form fields with values based on the crop coordinates. Check the jsCropperUI documentation for more details.
Here’s what our page looks like:

There are two other things to be aware of here:
First, the “image_tag” is displaying the “:default” style of the uploaded image. If you look back to the Upload model code above, that means it’s an image that’s been scaled down to at most 500×400 pixels. This is important, since we don’t want to display a full-sized image if someone’s uploaded a giant photo from a 10 megapixel digital camera!
Second, we’re telling the form helpers to create form fields for attributes like “x1″ and “width”, which aren’t attributes of our Upload model. To make this work, we need to add some virtual attributes to the model (virtual, because they’re not associated with any fields in our database table):
# models/upload/upload.rb
attr_accessor :x1, :y1, :width, :height
Now, when the form is submitted, the standard “update” action in the uploads controller will call “update_attributes”, just like any other form and controller:
# controllers/uploads_controller.rb
def update
@upload = Upload.find params[:id]
if @upload.update_attributes params[:upload]
flash[:notice] = 'Upload was successfully updated.'
redirect_to @upload
else
render :action => "edit"
end
end
To make this actually crop the image, we need to override the update_attributes method in the upload model:
# models/upload.rb
require 'RMagick'
def update_attributes(att)
# Should we crop?
scaled_img = Magick::ImageList.new(self.photo.path)
orig_img = Magick::ImageList.new(self.photo.path(:original))
scale = orig_img.columns.to_f / scaled_img.columns
args = [ att[:x1], att[:y1], att[:width], att[:height] ]
args = args.collect { |a| a.to_i * scale }
orig_img.crop!(*args)
orig_img.write(self.photo.path(:original))
self.photo.reprocess!
self.save
super(att)
end
What’s going on here? We want to crop our original, high-resolution image, but we used a scaled down version in the jsCropperUI to select our crop rectangle. To adjust for that, we need to check the pixel width (”columns”) for the original and scaled images, and compute a scaling factor. Next we prepare the four arguments for the RMagick crop function, which expects x1, y2, width, and height. We create an array with the arguments, convert to integer (they’re still strings, since they came from a text field in the form), and scale them. We can pass multiple arguments to a method by prefacing an array with an asterisk. That’s something new I came across in this project, and I suspect may come in handy again some time. The image is cropped, and then written back to disk, replacing the original.
“reprocess!” is a Paperclip method to re-generate thumbnails and other scaled versions of an image from the original. And finally, we call the true “update_attributes” method to handle things like the “description” or other actual attributes of our model.
So there you have it… a framework to deal with multiple image uploads to an associated model, with user-selected cropping.
I’ve packaged up the example code into a GitHub repository. It’s a fully functional Rails 2.2.2 app, assuming you have the Paperclip gem and RMagick already installed.
Comments and improvements are welcomed.
Posted in computing
20 Comments »
January 9, 2009
Went for PET scan #7 last week, and my doctor this week said it was completely clean, as expected. I’m now switching to twice a year for future scans. It was a little over two years ago that I had my Crohn’s surgery and started chemo, but it feels like forever — which is fine by me!
Fortunately, my Crohn’s has also been completely gone since the surgery, so for the last 18 months I’ve been healthier than any time in the last 20 years. The only undesirable side-effect of having working intestines is that actually digesting my food has caused me to gain considerable weight — 30 pounds compared to where I’ve been the last 10 years or so. This year I’m making some lifestyle changes… I’m not calling it a diet since diets tend to be temporary things. We’ll see how it goes, but the goal is to exercise more and eat healthier in general. It’s only been 1-2 weeks so far, but by writing it down here, I’m creating more incentive to continue.
Posted in cancer, crohn's, food/wine
4 Comments »
Recent Comments