Paperclip and Amazon S3

I recently added the ability to give each one of my posts a photo. It makes the entire site a bit less boring and gives it some human feel. I found the excellent paperclip plugin from the thoughtbot guys. This allowed me to easily attach pictures, have them resized and display them along side my posts. However, I ran into some problems with managing the upload files, no worries, Amazon S3 to the rescue.

Capistrano Deployment Problems

Each time you deploy your updated rails app with capistrano, it checks out the code in a new time-stamped directory and symlinks it to a “current” directory. The problem with this setup was that each time I updated my code, the uploaded files would be wiped out. I had a few options:

  1. Tell paperclip to store the files above the document root
    • Pretty simple, have to change the deploy recipe a bit
  2. Change my deploy recipe so “save” the files that have already been uploaded
    • Kinda cumbersome and a little “wrong” feeling
  3. Tell paperclip to store the files on Amazon’s S3
    • No changes to my filesystem or deploy recipe!

Paperclip Setup

In my Post model I’ve got

1
2
3
4
5
6
7
8
9
10
  has_attached_file :photo,
    :styles => {
      :tiny => "35x35",
      :preview => "175x175",
      :large => "300x300"
    }, 
    :storage => :s3,
    :s3_credentials => "#{RAILS_ROOT}/config/s3.yml",
    :path => ":attachment/:id/:style.:extension",
    :bucket => 'lengelzigich_blog_buckit'

I’m telling the paperclip plugin to resize my uploaded image in a few formats and also telling it that I want to store the files using S3 rather than the file system. I’ve added my amazon S3 key/secret code to a simple yaml file and I’m all set. Almost.

Install right_aws gem

Didn’t realize this right away but needed to install the right_aws gem.

Adaptive, Iterative and Agile Development is Fantastic

The ability to work in short bursts of agility leads to amazing results. The ability to quickly adapt to changing needs brings satisfaction. The ability to combine all of these with Ruby on Rails makes for a happy developer. Adaptive, iterative and agile development with ruby on rails is fantastic!

Some Monkey Guy

Some Monkey Guy

What I Want Right Now

When I “launched” this blog a few weeks ago I had the ability to create categories and write posts. That’s it. No comments, no tags (still don’t have those) no permalinks, no photos no nothing. Just a really simple system of posting in various categories. This was fine for a while, but I wanted more. So, as time permitted I slowly added new features. Here’s a rough timeline with some made-up version numbers

1.0 - posts and categories
1.1 - user accounts
1.2 - polished admin interface
1.3 - permalinks
1.5 - comments
1.6 - admin comments
1.7 - new comment notifications
1.8 - photos

Together these would have taken a while, but as separate pieces they were simple digestible easy to complete tasks, perfect for my workflow.

Ship It, LDO

I would have loved to have all of these things and more when I launched originally but it wasn’t in my time budget so I had to break it up this way. I just needed to get something up and running, so I went with the most basic of basics. Turns out, I found some things that I could do with out right away (tags, search, ratings) and found some things that I wanted (permalinks, comments, photos). Everything bubbled up according to it’s importance and so far everything feels just right. When it doubt, just ship it. Like duh, obviously.

Rails Tie-In

If you haven’t realized quite yet, Ruby on Rails makes this agile/iterative approach super easy. Between migrations, built-in helpers and BDD I was able to add all of this new functionality piece by piece knowing that I wasn’t going to break anything I already had. Plus it didn’t take very long (learning curve not withstanding).

In a world dictated by client requests and boss-based to-do’s I don’t often get the chance to work like this, but for now I’m cherishing every moment.

Learning Best Practices, Idioms and New Languages

A few days ago I was listening to an episode of the StackOverflow Podcast and Jeff Atwood said something interesting about how he did a lot of reading as a kid but didn’t do much discussing about said reading with other people. The problem being that he had a lot of words that he wasn’t sure how to pronounce outside of how he had originally determined they should be pronounced. I was thinking about how this translates to code constructs and programming styles and how it’s easy to get stuck in your newb ways.

How Do You Say That?

I’m sure we’ve all experienced what Jeff was talking about, you’re reading something and you come across the name of a person or a place and you’re not really sure how to pronounce it but for the sake of moving through the material your brain comes up with something and you continue to use that each consecutive time it comes up in the material.

It’s only the next day when you’re talking about the text with a friend that you hear their alternate pronunciation of the word. Sometimes neither or you are sure what the correct pronunciation is, but you now spend the rest of the conversation saying each pronunciation, so as not to be rude, when referring to the word in question.

Learning PHP

A lot of programmers start out learning PHP. It’s easy to learn, make something, lots of resources etc. etc. However, I think that you tend to do a lot of the “brain deciding how to do this previously unknown thing” decision making while you’re learning. There was a post on The Daily WTF today about somebody who basically re-implemented the functionality of $_GET using their own hacked together POS method. It’s good for a laugh sure, but it’s not that unreasonable when you think about it.

Imagine you’re learning PHP and you’re like most geeks, introverted, you want to accomplish this goal of learning a new language, but you’re not planning on spending any time discussing it with other people. This is especially likely if you’re not learning in a work environment with other people. Since you don’t know a lot of the idioms, best practices and commonly used syntax you end up figuring things out and deciding that’s just how it’s done. I only use PHP in this example because of its wide use and forgiveness when not sticking to accepted practices (are there any?).

You find ways to do things and you stick with them, for good or bad, until you find out a different way.

Quit Being an Introvert

Do yourself a favor and get over keeping to yourself, you’ll be a better programmer and you might learn something about social interaction.

  • Join mailing lists (*and participate*)
  • Join forums (*and participate*)
  • Attend local in-person live events
  • Find some AIM/YM/MSN/Gtalk buddies who you can bounce ideas off of
  • Seek the advice of the more experienced

Paging Dr. Cache

When I launched this blog last week I thought it was slow because of my small (256MB) Slice at Slicehost. Then I read about people optimizing their rails installations, so I optimized and it got a bit faster. But, it was still slow. So I read up on optimizing the speed and memory usage of Phusion Passenger aka mod_rails. I made some enhancements and it got a bit better. Problem was, it was still REALLY slow. For a second I got a bit discouraged, I thought to myself “Is this the kind of performance I can expect from a simple rails app?”, I quickly reminded myself that I was probably just not realizing that there was something I could do to make things faster. Then I remembered something I read about caching.

Page Caching is EZ

Following the super-duper-awesome page caching tutorial on the RailsEnvy blog, I quickly setup some caching for my posts controller. I also got my sweepers happening to make sure I’m not serving my guests anything old and stale (bad host indeed).

1
2
3
4
5
class PostsController < ApplicationController
...
  caches_page :index, :show
  cache_sweeper :post_sweeper, :only => [:create, :update, :destroy]
...

All together it took about 15 minutes, I spent some extra time troubleshooting a problem that was the result of naming my sweeper PostSweeper.rb rather than post_sweeper.rb.

mod_rails configuration

In the RailsEnvy tutorial they mention setting up some custom mod_rewrite rules to handle telling Apache to serve your cached pages instead of passing the requests on to your mongrel instance. From what I read in the Passenger/mod_rails user guide, this wasn’t necessary, plus they mention that mod_rails doesn’t play well with mod_rewrite anyhow, so I didn’t change anything about my vhost config.

PLS 2 BEE BENCHMRKIN

I read all about how cool and fast page caching was and not that I didn’t believe it, but I was curious how cool and fast it really was. To test any performance improvements I used Apache Benchmark (ab for short).

The test consisted of running 500 requests with a concurrency level of 5

1
$> ab -c 5 -n 500 http://www.lengelzigich.com/

I ran this three times from start to finish, waiting about 30 seconds between each run. Then I ran it a fourth time and saved those results.

Before Page Caching

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
Server Software:        Apache
Server Hostname:        www.lengelzigich.com
Server Port:            80
 
Document Path:          /
Document Length:        4599 bytes
 
Concurrency Level:      5
Time taken for tests:   92.220691 seconds
Complete requests:      500
Failed requests:        2
   (Connect: 2, Length: 0, Exceptions: 0)
Write errors:           0
Total transferred:      2552000 bytes
HTML transferred:       2299500 bytes
Requests per second:    5.42 [#/sec] (mean)
Time per request:       922.207 [ms] (mean)
Time per request:       184.441 [ms] (mean, across all concurrent requests)
Transfer rate:          27.02 [Kbytes/sec] received
 
Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:       74  392 2023.8     78   19114
Processing:    96  115  34.8    103     536
Waiting:       94  111  24.8    100     207
Total:        172  508 2022.9    183   19215
 
Percentage of the requests served within a certain time (ms)
  50%    183
  66%    187
  75%    199
  80%    223
  90%    249
  95%    276
  98%   7114
  99%  11201
 100%  19215 (longest request)

After Page Caching

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
Server Software:        Apache
Server Hostname:        www.lengelzigich.com
Server Port:            80
 
Document Path:          /
Document Length:        4602 bytes
 
Concurrency Level:      5
Time taken for tests:   24.150369 seconds
Complete requests:      500
Failed requests:        0
Write errors:           0
Total transferred:      2553500 bytes
HTML transferred:       2301000 bytes
Requests per second:    20.70 [#/sec] (mean)
Time per request:       241.504 [ms] (mean)
Time per request:       48.301 [ms] (mean, across all concurrent requests)
Transfer rate:          103.23 [Kbytes/sec] received
 
Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:       74   88 180.5     78    4008
Processing:    95  119  36.3    105     494
Waiting:       93  116  35.4    103     492
Total:        171  208 183.2    186    4109
 
Percentage of the requests served within a certain time (ms)
  50%    186
  66%    192
  75%    202
  80%    218
  90%    247
  95%    261
  98%    277
  99%    392
 100%   4109 (longest request)

The Results

  • 4x improvement in requests per second
  • Time per request reduced by 75%
  • 100% of requests were served in 4 seconds or less compared to 15 seconds or less

Overall I’m more than pleased with the results and plan on taking a look at the next RailsEnvy tutorial on ActionCaching.

Instant Gratification through Unanswered Posts

I’ve been a member of Rails Forum for over a year now, since January 2007 to be exact. In my first year and 3 months I managed to make about 90 posts. Looking back these are mostly “newb” questions and solicitations for getting on the right track. This was when I was casually using rails and getting up to speed. In the last two weeks I’ve made about 40 posts, 95% of which have been answering the same type of questions that I was asking last year. This type of reciprocal system is a great way to learn and instant gratification.

Unanswered Posts

Most forums have an unanswered posts link that show you all of the posts where no-one has yet replied (duh). I’ve found this to be a great way to become a “first responder” to a lot of problems. Not only do I get a shot at answering a question in my own way, without being biased or lead by other member’s answers, but I get some satisfaction from seeing a list of recently answered posts all with my name on them.

Teaching as a Learning Tool

Personally I’ve always found that teaching or explaining something to someone is a great way to improve my personal understanding of that particular topic. This has been an important part of improving my knowledge of the “why” in all of this. It’s easy to reply to a person and give them the answer, but providing the “why” component, or having to go look it up and then provide it, make a huge difference in furthering my whatever fu.

Get Answering!

  1. Pick a topic or skill you’re learning more about
  2. Find a community
  3. Start answering
  4. ???
  5. Mentally profit

Learning Rails: Namespaced Controllers

A common requirement of a visitor facing web application is that the administration component of the app is behind a login with a different layout, style sheet and feel. Rails 2.0 makes this very simple with namespaced controllers. On a recent project the specs called for the administration to live under an /admin path, simple enough.

Creating the Admin Interface

1
$> script/generate controller admin/employees index show new create edit update

Perfect, now I’ve got my new controller and some views.


  /app/controllers/admin/employees_controller.rb
  /app/views/admin/employees/
    /app/views/admin/employees/index.html.erb
    /app/views/admin/employees/show.html.erb
    /app/views/admin/employees/new.html.erb
    /app/views/admin/employees/edit.html.erb

We’ll need to create a new layout and style sheet for our admin interface:

1
2
$> touch app/views/layouts/admin.html.erb
$> touch public/stylesheets/admin.css

A quick edit to our routes file and everything is in place:

1
2
3
map.namespace :admin do |admin|
  admin.resources :employees
end

In a few short steps we’ve got everything we need for our /admin area. Now we just have to build out all of the controller actions, write all of our tests, add the markup to the views… and then we have to do it all over again for the public facing controller.

The Drawbacks

At this point I realized how un-sexy this technique is. For each Model that I want to display to the public and edit in the admin I have to create two controllers, two views, two layouts, two style sheets and twice as many bugs, typos and frustrations. GAH. By the time you write all of the specs for each controller you’ve got some ridiculous code:test ratio and you never want to look at TextMate again.

The Expense of “Keepin’ it DRY

As a rails developer you should always think about “Keepin’ it DRRRYYYY” but sometimes the pursuit of DRY just isn’t worth it. As far as I can tell, keeping the admin and public controllers, views and tests separate and DRY adds way more complexity and confusion when you use namespaced controllers. I just don’t think it’s worth it

Alternatives

  1. You can create named routes to satisfy the “/admin” requirement
  2. Write an application controller method to determine which template to render (based on admin/public visitor status)

That’s it really, it doesn’t take much to keep things simple® and avoid a bunch of duplicate-in-concept code. The next time you reach for namespaced controllers to satisfy this type of functionality, think twice, it might save you a lot of trouble.

Reinventing Wheels

It’s been about two weeks since I started writing the ruby on rails app for this blog. I recently took a look at some of the established RoR blogging engines and this feels more like a somewhat circular rock. Even though this app is lacking a lot of the regular features of a blog, I’m extremely happy with how it turned out.

Build to Learn

One of the things that I realized early in my programming career was that reading about how to do something was nice, but I never felt like I really understood it. However, when I started actually building something everything started falling in place. I think this is a pretty standard realization for a lot of developers and it’s always something I keep in mind when learning a new technology. Enter Ruby on Rails. Even though I read a ton of stuff, watched lots of videos, subscribed to podcasts and purchased expensive books, I didn’t realize how much I was missing until I set out to plan, build and deploy this application.

Referencing the Reference Books

By a huge margin the best ruby on rails book I found was The Rails Way (non affiliate link btw). There was just something about it’s straight forward nature, clever writing and almost-but-not-quite reference book feel that made it so easy to use. There was a great post on the Signal v Noise blog the other day about years of irrelevance where David spoke about how it took him some time to get up to speed with ruby’s syntax, idioms and just how things worked. I think I’ve finally reached that point with rails, the more and more I used the The Rails Way the less and less I needed it. Combine this awesome book with building this app and I think I made it through the learning curve faster than I would have following tutorials or watching videos.

What I Learned

Here’s just a short list of things I learned while building this app. I plan to expand this particular concept into a series of posts.

  • Using RSpec for BDD Testing
  • RESTful controllers
  • Ruby syntax and idioms
  • Customizing and extending Rails
  • Deployment with Capistrano
  • Git

Sadly I had spent some time already reading about all of these, but never understood how far off I actually was.

When NOT to Reinvent

While I’m hailing the virtues of building your own stuff from scratch it’s important to know when “rolling your own” is a bad idea. First, if you’re doing work for a client chances are you’re going to increase your profitability by finding a solution that’s been built and tested and proven to work, do you really want to build your own Authorize.net processor when you can use Active Merchant instead? Secondly, if you don’t have the time and patience to work on your project with the understanding that you’re trying to learn as you go, you run the risk to slapping together something that’s a hodgepodge of bad code and shortcuts, which will be more trouble down the road.

App Delivers; Would do Again

Like I said earlier, while I don’t have everything I’d like in this app, I’ve learned more doing this than I would have reading about how to do this so I’m happy. I know everything about this app and can add to and improve it as time goes on. Perhaps most importantly I have the satisfaction of having built something that’s now facing the world which is one of the more underrated accomplishments in software development.