my current Work Stack

  • iOS Objective-C
  • Ruby
  • Mongo
  • Rails/Sinatra
  • jQuery
  • Capistrano
  • Passenger
  • Apache.Nginx
  • Heroku
  • Nodejs
last edited 02.10.2012

here's all my posts so far

02/10 Using the Facebook SDK in an IOS Static Library
04/11 Managing Development or Sometimes work gets in the way of work
12/21 Git Stash: For when your boss|clients|life priorities change
12/09 Picker Fields in Titanium
11/30 An Update on Raphael JS and Charts
10/08 How to make a Native App Form that doesn't suck with Titanium
09/23 Notification Subscriptions in Gowalla
09/21 Developing an API in Rails
08/26 I was promised Event Driven APIs and hoverboards. Where are my hoverboards?
08/14 A Node.js wrapper for Gowalla
08/09 Phusion Passenger Tweaking: Apache stuck in Sending(W)
06/28 HTML 5 is here and breaking old hacks we should have never done!
06/26 Simple PDFkit example in Rails 3
06/23 Raphael.serialize
06/12 Serializing RaphaelJS
06/11 Rails 3 beta4 destroyed my Tie Fighter
05/21 Rails 3 and Shoulda
05/13 Using yaml to configure default options for Paperclip
05/07 It's OK to not be pretentious
04/23 Snippet #1
04/21 I Need Closure
04/16 The Good and Bad of Github
04/08 Fun with Beards, or at least mine

here's some tweets I made

Using yaml to configure default options for Paperclip

I love Paperclip. It's an awesome tool for a part of web development which has always been annoying. Now I'm waiting on sending email to get less annoying, (although Rails 3 might take care of that. Might.)

Anyway, the only thing I don't like about Paperclip is the default setting for url and path. Which is currently "/system/:attachment/:id/:style/:filename".

Do you see the problem? I use capistrano so the "/system" doesn't bother me. My problem is the lack of :class. Without :class any attachments with the same name will collide and equal ids in different models will overwrite each other.

Why shouldn't my Album have a cover image and my Book have a cover image?

In Paperclip you can send in custom options to every attachment you have a la:

1
2
3
4
5
6
7
8
9
10
11
has_attached_file :logo,
    :styles => {
      :tiny => "35x35",
      :preview => "175x175",
      :large => "300x300"
    },
    :storage => Rails.env.production? ? :s3 : :filesystem,
    :s3_credentials => "#{RAILS_ROOT}/config/s3.yml",
    :path => Rails.env.production? ? ":attachment/:id/:style.:extension" : "#{RAILS_ROOT}/public/uploads/:attachment/:id/:style.:extension",
    :url => Rails.env.production? ? ":attachment/:id/:style.:extension" : "/uploads/:attachment/:id/:style.:extension",
    :bucket => 'organization_logos'

But I don't like typing all that. And wait, there's more. See me using

1
Rails.env.production? ? blah : blah

I use S3 in production and my filesystem for dev and testing. But I don't like typing that either. I'd rather make a yml file that looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
development: &non_production_settings
  url: "/system/:class/:attachment/:id/:basename-:style.:extension"
  path: ":rails_root/public:url"

test:
  url: "/system/:class/:attachment/:id/:basename-:style.:extension"
  path: ":rails_root/public:url"

staging:
  url: "/system/:class/:attachment/:id/:basename-:style.:extension"
  path: ":rails_root/public:url"

production:
  url: "/system/:class/:attachment/:id/:basename-:style.:extension"
  path: ":rails_root/public:url"
  storage: ":s3"
  bucket: "my-bucket"

To do that I just made an initializer that redefines the Paperclip::Attachment.default_options method:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
module Paperclip
  class Attachment
    def self.default_options
      return @default_options if @default_options

      @default_options = {
        :url => "/system/:attachment/:id/:style/:filename",
        :path => ":rails_root/public:url",
        :styles => {},
        :processors => [:thumbnail],
        :convert_options => {},
        :default_url => "/:attachment/:style/missing.png",
        :default_style => :original,
        :storage => :filesystem,
        :whiny => Paperclip.options[:whiny] || Paperclip.options[:whiny_thumbnails]
      }

      if defined?(RAILS_ROOT) and File.exists?("#{RAILS_ROOT}/config/paperclip.yml")
        @default_options.merge!(YAML.load_file("#{RAILS_ROOT}/config/paperclip.yml")[RAILS_ENV].symbolize_keys)
      end
    end
  end
end

Done, let the DRYness begin. You'll have to change the yml file of course.

blog comments powered by Disqus