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

Hi!
I'm Jonathan, a web developer in Austin, TX. I'm into fun apps, Ruby, programming creatively, TDD, and one line code challenges.

Here's the last thing I wrote on here:

Using the Facebook SDK in an IOS Static Library

The new Facebook SDK is great. The Single Sign on is a much more fluid login process for the majority of Facebook users. But the old dialog, despite being ugly, let us put it anywhere, without any problems.

We have a static library that uses Facebook, that our partners can drop into their own app. The new SDK causes some problems. If they are already using Facebook, the methods in the App Delegate collide. Even if they aren't using it, you have to convince them to update their plists with your schemes.

Facebook seems to have forgotten to put some options into the new SDK, but if we take a tour through the source code, we see this method:

1
2
3
4
5
- (void)authorize:(NSArray *)permissions {
  self.permissions = permissions;

[self authorizeWithFBAppAuth:YES safariAuth:YES]; }

Changing those two YES's to NO's makes the app revert to the old dialog. No plist entry needed, no entry points in the App Delegate, just good old web view callbacks.

The only problem for us is that distributing the Facebook SDK with our library would cause headaches for our partner's developers. They would have two clashing FB SDK's.

So we expose the method we want and create a category to write a new method using the private method authorizeWithFBAppAuth.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// expose Facebook API we need
@interface Facebook (Private)
- (void)authorizeWithFBAppAuth:(BOOL)tryFBAppAuth
                    safariAuth:(BOOL)trySafariAuth;
@end

// Facebook category for extending @interface Facebook (Bypass) - (void)bypassAuthorize:(id<FBSessionDelegate>)delegate; @end

@implementation Facebook (Bypass)

- (void)customAuthorize:(id<FBSessionDelegate>)delegate { // you can set your own perms here _permissions = [NSArray arrayWithObjects:@"email", nil]; _sessionDelegate = delegate; [self authorizeWithFBAppAuth:NO safariAuth:NO]; }

@end

I just dropped that in the controller where I needed it, although you could always include it from its own source files.

Comments

Managing Development or Sometimes work gets in the way of work

I haven't posted in a long time. Luckily, it's not because I haven't been learning anything, it's just that most of the things I've been learning aren't as programming related as they are "business tech" related.

Your company grows and you start spending time making phone calls, collaborating with partners, talking with users, writing documentation, etc.

So instead of coding snippets I want to talk about coding in a fast paced environment, especially when you have a lot more to do than just code.

I am managing development at a startup, so this is also my intended audience. Also, I screw up all the time.

  1. Set small goals in short timeframes

    Big vague goals are difficult to accomplish and difficult to break into chunks to assign to different people. I also find that checking things off builds morale for everyone invested in the code. We do everything in two week sprints and plan the week every Monday.

  2. Set a whole lot of them way in the future

    Today you should know what you are going to do in six weeks. Even though the goals themselves are small, they should reach far into the future.

  3. Don't be afraid to change them

    Understand that you don't really know what you are going to do in six weeks. Things come up: opportunities that take precedence or failures in ideas or technologies. Things change and so do you.

  4. Don't be afraid to never to do some of them

    You will not and should not complete all of the goals. They are set far into the future to give you direction now. But by the time you get there, they will change. Your job is to make the best ones, the ones that will move your company forward, emerge.

  5. Know your coders

    You need to know your coders and their strengths and weaknesses. Not just what they are good at coding, but also what motivates them, what environment is best for them, when do they do their best work. Also, understand what part of coding they love, and what they hate. And if they don't love any of it, get rid of them. :)

  6. Trust your coders
    If you learn to trust your coders based on their strengths and weaknesses, your tech will make progress much more quickly. Assign tasks and let them do them. Or better, yet, allow them to choose tasks. But you have to trust that they will choose the right one for them and that they will do it.

  7. Don't trust their code (or yours)

    Because we all make mistakes and their code is your responsibility. Take the time to code review, have them refactor if required, make small tweaks yourself but use them as teaching opportunities. Oh, and most of all: AUTOMATED TESTS

  8. Limit your scheduled phone calls to either 1 per day, or all of them in one day.

    Phone calls kill. You're no good before them and no good after them. And no one is any good during them. I prefer the one per day method, just knowing that an hour of my day will be phone calls with partners or support. Then I plan accordingly.

  9. Figure out what time of day is best for certain tasks and schedule around that

    This really goes for anything you do in your life. When are you best at exercising, reading books, spending time with your family? I know in the morning I'm easily distracted, so that's when I schedule calls, do email and write documentation. In the afternoon I can creatively solve all of the world's complex problems and hunt down the most deceptive bugs. Late at night, though, I can hunker down and churn out millions of lines of rote code. You might be completely the opposite.

Comments

Git Stash: For when your boss|clients|life priorities change

I discovered git stash awhile ago and have gotten a lot of use out of it.

Basically, it takes your working changes and stashes them somewhere, reverting back to the HEAD. You can retrieve those changes later like they never went away. This allows you to change branches when you want without committing things.

Since you can have lots of stashes and refer to them by name, you can also try one solution, benchmark it, then try a different one and in the end, only apply the best one.

I've been using it this way for awhile, but today I discovered git stash branch which lets you move your stash to a new branch.

Today I was asked to roll back all my working changes for a release, but keep those changes for the next release. Our priorities changed. In the past I would have done a commit, then made a branch, then rolled back a commit. But with git stash branch I just typed:

1
2
git stash
git stash branch <newbranchname>

Done.

Comments

Picker Fields in Titanium

I see a lot of questions in the Titanium Developer Forum about hiding the Keyboard when you click a text field. Typically you want to bring a Picker up when you do this.

Almost every response says "Just blur the field in a focus handler" While I guess this "works" you can still see the keyboard slide in and out. Especially on the iPhone 3G and OG.

I present a better way.

First, create your Picker and the view, and provide a toolbar to cancel or choose your selection.

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
var pickerView = Titanium.UI.createView({
  height:260,
  bottom:-260
});
var cancel =  Titanium.UI.createButton({
  title:'Cancel',
  style:Titanium.UI.iPhone.SystemButtonStyle.BORDERED
});
cancel.addEventListener('click',function() {
  pickerView.animate(slide_out);
});
 
var done =  Titanium.UI.createButton({
  title:'Done',
  style: Titanium.UI.iPhone.SystemButtonStyle.DONE
});
done.addEventListener('click', function(event) {
  specialField.text = picker.getSelectedRow(0).title;
  specialField.color = "#333333"; // no more hint text
  pickerView.animate(slide_out);
});
 
var spacer =  Titanium.UI.createButton({
  systemButton: Titanium.UI.iPhone.SystemButton.FLEXIBLE_SPACE
});
 
var toolbar =  Titanium.UI.createToolbar({
  height: 43,
  top: 0,
  items:[cancel,spacer,done]
});
pickerView.add(toolbar);
window.add(pickerView); // do this last or set a z-index

You probably already had something similar to slide in when the textField was focused. Notice I didn't put the picker in this example.

Now comes the key part. Make a view and a label that look like a textField. Luckily, Titanium (or javascript really) lets you assign random attributes to an existing object. (OK, so it's really an associate array but we're going to use Object Notation so it looks like a traditional attribute)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

var specialFieldView = Ti.UI.createView({
  borderColor: "#a6a6a6",
  top: 240,
  width: 260,
  height: 40
});
var specialField = Ti.UI.createLabel({
  color: "#bbb",
  left: 10,
  width: 260,
  height: 40,
  text: "Choose Special Thing", // used like hint text
  font: {fontSize: 16, fontWeight: "normal"}
});
specialFieldView.add(specialField);

specialFieldView.addEventListener('click', function(event) {
  pickerView.animate(slide_in);
});

So the key now is to just make the View and Label combination look like your Text Fields. It's pretty easy to do. If you want to use Hint Text, just make sure to change the text color to something darker once the value is set.

Comments

An Update on Raphael JS and Charts

I've been a fan of Raphael JS for a long time. It's a javascript vector graphic library that (IMHO) blows canvas stuff away. Canvas definitely has its uses, but most of the stuff I see being done in canvas can be done more easily and more efficiently in SVG.

For a couple of years I've been using the Google Charts API. I've never been a fan of Flash graphs unless you need the bells and whistles of interactivity and zooming. So I've generally stuck with Google. However, I've never been pleased with the look and feel, and building URLs feels a little odd sometimes.

In comes Raphael Charts, or gRaphaƫl. It's simply a plugin for raphael from the creators of raphael. The demos are beautiful and they offer basic levels of interactivity with very little effort. And importantly; no Flash.

I had the pleasure of using it this evening and roughly clocked 6 minutes from the time I entered the raphael URL to the time my first pie chart was finished.

Here's some quick sample code in haml

1
2
3
4
#chart
:javascript
  var r = Raphael(document.getElementById("chart"));
  r.g.piechart(120, 120, 100, [#{@game.results.collect{|r| r.winnings}.join(",")}]);

Comments

How to make a Native App Form that doesn't suck with Titanium

Some things are much more difficult to do in a native app than on the web. But forms are not one of them. Both iOS and Android give us simple tools to make form interaction nice and easy.

Unfortunately the Titanium docs make it almost impossible to figure out. Don't get me wrong, the docs are great, and the Kitchen Sink app they supply covers 80% of the things you can do. But making a nice form was somehow left off.

In particular, I was looking to make a form with sections that are stacked together, had a hint and no label, and led you from field to field. After tons of searching docs, Q&A and googling, I did it.

I'll show you the code first and then go through it.

This is in a file I called login.js that is called by a window.

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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
var window = Ti.UI.currentWindow;
var loginField = Ti.UI.createTextField({
  value:'',
  width:300,
  height: 40,
  left: 5,
  hintText: 'Username',
  returnKeyType:Titanium.UI.RETURNKEY_NEXT,
  borderStyle:Titanium.UI.INPUT_BORDERSTYLE_NONE
});

var passwordField = Ti.UI.createTextField({
  value:'',
  height: 40,
  passwordMask: true,
  hintText: 'Password',
  width:300,
  left: 5,
  borderStyle:Titanium.UI.INPUT_BORDERSTYLE_NONE,
  returnKeyType:Titanium.UI.RETURNKEY_DONE
});

loginField.addEventListener('return', function(event) {
  passwordField.focus();
});

passwordField.addEventListener('return', function(event) {
  // submit your form here
});

var table = Ti.UI.createTableView({
  style: Ti.UI.iPhone.TableViewStyle.GROUPED,
  rowHeight: 40
});

var section = Ti.UI.createTableViewSection({headerTitle: "Sign in"});
    
var row = Ti.UI.createTableViewRow();
row.add(loginField);
row.hasChild = false;
row.className = "field";
section.add(row);

var prow = Ti.UI.createTableViewRow();
prow.add(passwordField);
prow.hasChild = false;
prow.className = "field";
section.add(prow);
table.setData([section]);

window.add(table);

It's pretty simple really.

The first part creates a username and password field. The key parts here are:

1
2
3
hintText: "Username",
returnKeyType:Titanium.UI.RETURNKEY_NEXT,
borderStyle:Titanium.UI.INPUT_BORDERSTYLE_NONE

  • hintText adds the helper text so you don't need a label.
  • returnKeyType basically changes the text on the input keyboard return key.
  • borderStyle we set to none so that we can let the table view handle the borders.

In the next part we set event listeners for when that return key is pressed. We can auto forward the user to the next field using .focus();

Next we create a table that is GROUPED, add our inputs to simple rows and put them in the table. Make sure the row height is the same as the input height so that the rows appear to be the inputs.

Here's the result:

Comments

Notification Subscriptions in Gowalla

This is follow up to my post on Event driven APIs.

It seems Gowalla got smart about apps checking in on them all the time and implemented "Realtime Updates"

I can't wait to reimplement my polling in my Nodejs Gowalla wrapper

Comments

Developing an API in Rails

At work it's finally time to open our "API" to some real use. The reason I use quotes around API is that our current implementation does almost nothing and is use by no one. But now we need a real API for our mobile apps and some future third parties.

I've written a few APIs in the past but always exclusively for internal use, and while my next one is primarily for us, I know that in the near future we will need to let some intruders into our home.

So I spent all last week planning the API and sifting through existing ones that I admire. I even talked to some API authors about the problems they had faced.

Here's some references I used:

The main problems I heard from existing API authors:

  1. Regret integrating the API into existing controllers, via respond_to
  2. Inability to change API without breaking third party apps
  3. Lack of knowledge/control of third party developer actions
My approach:
  1. At this time it doesn't make sense for me to split an API out to its own app, using Sinatra or node for speed, because we don't have the traffic. However, I took the regrets of others to heart and decided to completely namespace the api, avoiding mixing logic. Yes, some of my controller logic will be duplicated, but I don't care. If I need to split it out, it's easy; very easy.
  2. I considered using versioned APIs. A simple approach in Rails once you are namespaced is simply to namespace versions in your api namespace. But I didn't want to copy code and add namespaces. So I decided to stick to RESTful APIs for public consumption and save anything different for our internal use. That way, I can change the api however I deem fit, without breaking the RESTful portions. Third parties will just have to do more work than us.
  3. This last problem doesn't seem important to me now, but could in the future once there's a pesky consumer. So I developed a tiered access level of API keys. To the typical public consumer, nothing will seem different, but internally they will have an access level of 1, be restricted to certain requests, and have suspicious activity logged. I decided to create a model that feeds to MongoDB where I can just dump suspicious activity and calculate use rates separately.

At this point I've finished the foundation of the API.

Here are the key features:

  • All controllers are namespaced into api.
  • Every request requires API_KEY in header and authenticates its access level. This is handled in the api namespace base controller.
  • Receives and authenticates optional HTTP Basic User Authentication.
  • Controllers inherit from API::BaseController and can optionally call require_api_login (for HTTP Auth) and require_access_level(num) to restrict access.

Now that all that is finished, with 100% test coverage, I can easily add RESTful controllers to expose JSON and XML per model. It's going swimmingly.

Comments

I was promised Event Driven APIs and hoverboards. Where are my hoverboards?

I've been thinking a lot lately about real time fancyness and event driven async programming and how that fits really well with the American consumer mentality. We want exactly what we want, exactly when we want it.

This is also how we consume APIs. I see pollers and timeIntervals set up all over the place to continually ping for new information. How many of us have set up a TTL cache or a background or cron job to feed off twitter search? I know I have. And I always feel a little dirty doing that.

Recently I wrote a node.js gowalla library and I included built in polling for checkins and item activity. All of the lib activity is event driven, but consuming the API is still a timed interval. It made me realize that these companies could increase their efficiency by offering an event driven API.

I'm definitely not the first person to propose this. A google search yields tons of results, mostly failures. I presume they're failures because they are all XML based. (Oh! I went there!) It seems difficult, but I wonder if a simpler approach could yield strong results.

Could it be as simple as registering a RESTful POST back to your domain? You'd have to think about security, like limiting API keys to domains and possibly encoding the data with a key that you've only shared with the client. But something simple like that could cut down total requests dramatically.

If I'm pinging twitter every 5 minutes for a search result that occurs 100 times a day, I've cut my requests to 25%. I'm incurring a little more overhead from initiating the requests, but I think it still works out to less time on the network, plus you are pushing out each bit of data only once, instead of the same 20 tweets over and over again.

I don't expect anything like this to pop up soon, but it sure would be nice. And then I wouldn't have to keep writing the pollers that make me feel guilty.

An exercise for the reader: Let's say the twitter search we are polling has 1 new tweet every 2 seconds, because we searched for Bieber or some slang word that the kids are all about. How could an event driven callback improve efficiency there? Would we need some sort of limit and queueing? Could this actually make the data more accurate?

Comments

A Node.js wrapper for Gowalla

Tonight I took some time off from coding for other people and did something fun. I ended up with a mostly complete wrapper for Gowalla in Node.js.

I did some searching and found one, but it wasn't what I was looking for. First it was outdated and second, it was just a rehash of the already simple JSON API.

The main thing I was looking for was more object relatedness. (That's a term I just made up). Essentially I wanted to chain things.

For example:


gowalla.user("jspies").pins();

So I made it.

Comments

Phusion Passenger Tweaking: Apache stuck in Sending(W)

For some reason I found this information missing from Google searches so I'm going to write one up and wait for Google to index it.

I was having a problem where Apache's process list would slowly begin to fill up with requests stuck in a Sending (or W) state. After my MaxClients was reached, the server would effectively shut down.

Searching for "apache processes stuck in sending W state" yields a whole bunch of people using mod_php and Apache. And it seems that no one ever solved it in a reproducable way. And I'm using Phusion Passenger anyway.

So it seems I had to use my brain. This server:

  • Low traffic
  • lots of virtual hosts
  • No code pushes coincided with the problem.

I couldn't find any other symptoms anywhere. Ruby wasn't getting stuck. The CPU load was low and memory looked normal. All the Apache stats were good.

Then I looked at passenger status.


sudo passenger-status

And I saw only 6 instances. If I ran passenger status again I could see those instances swapping rapidly between one site and all the others.

I found in the Passenger docs, PassengerMaxPoolSize, which defaults to 6. In my passenger.load (Ubuntu config mod file) I added:

1
2
PassengerMaxPoolSize 20
PassengerUseGlobalQueue on

Voila!

It seems one site had starting to get heavy traffic and was constantly pulling instances. But Passenger didn't handle the context switching very well. By giving more pools, that site is able to keep a few all the time so there's no switching.

Comments

HTML 5 is here and breaking old hacks we should have never done!

Today I had an old form bubble up from the past and bite me. We were using "custom" attributes on form fields called required for use with javascript. Which of course we shouldn't do.

We were made aware that the form wasn't submitting in Safari. I immediately check the form in Chrome and Firefox; it worked in Firefox and not in Chrome. What do Chrome and Safari have in common? Webkit and HTML 5 actually being added in.

You'd think this wouldn't be a problem since all the fields marked as required are required, however, we jacked that up. HTML says that boolean attributes should be blank, or really anything else. Most people use the name of the attribute.

1
2
checked="checked"
required="required"

We used required="true" and required="false", making all fields required. Hooray me and hackery!

Comments

Simple PDFkit example in Rails 3

I couldn't find a good example of using PDFkit in rails, so I figured it out and am now making one.

1
2
3
gem 'pdfkit' # add in Gemfile

bundle install

Also register a pdf mimetype in config/initializers/mime_types.rb (Thanks to ravi for pointing this out)

1
Mime::Type.register_alias "application/pdf", :pdf

Here's what I do in my controller:

1
2
3
4
5
6
7
8
9
10
respond_to do |format|
  format.html
  format.pdf {
    html = render_to_string(:layout => false , :action => "show.html.haml")
    kit = PDFKit.new(html)
    kit.stylesheets << "#{Rails.root}/public/stylesheets/screen.css"
    send_data(kit.to_pdf, :filename => "labels.pdf", :type => 'application/pdf')
    return # to avoid double render call
  }
end

It's pretty simple. The main thing I had to do was specify the format as html in the render_to_string call. You could make a show.pdf.haml I guess, but we're converting html to pdf so why duplicate the view?

Comments

Raphael.serialize

Last time I wrote a little about serializing SVG objects from RaphaelJS. I need to store them in a database and pull them back in. As usual I opted for a JSON string.

I've put the serialize code as a RaphaelJS plugin on github at jspies/raphael.serialize.

The upside is that the plugin runs through all the objects on save, whereas other techniques I've seen require monkey patching Raphael methods and storing references to the objects.

The downside is that each type of object is different and requires a special case.

Feel free to fork and add object cases.

One thing I would really like to do is separate the process from the output so that exporting into XML or YML or some custom JS object would be trivial.

Comments

Serializing RaphaelJS

I'm in love with Raphael JS (a javascript library for SVG graphics). For the things I need to do, this is far more exciting than just using canvas. And Dmitry Baranovskiy, the author of RaphaelJS has it working in IE by using VML.

I wanted to store my drawings and load them later as SVG instead of saving them as bitmaps. I started by monkey patching Raphael to keep an array of the objects I was interested in but it began to get hairy with paths and sets.

After reading an excellent post by Ben Barnett I changed my strategy to pull the nodes out of the Raphael object when I needed them.

The main trick is that (as of 1.4.3) Raphael stores a top and a bottom and, you guess it, a linked list of nodes.

Here's the gist.

Comments

Rails 3 beta4 destroyed my Tie Fighter

UPDATE: Turns out it wasn't just Rails3 beta4 that shot down my tie fighter operator. It was the combination of it and Ruby 1.9.1. Switching to 1.9.2 or 1.8.7 work fine. So now I get to wait on Rails to release 3 and Ruby to release 1.9.2 before I feel comfortable deploying anything.

END UPDATE

Railsconf brought rails beta4. Yay! or not. I get this immediately:

undefined method `<=>' for class `ActiveSupport::Multibyte::Chars'

My Tie Fighter Operator! No!

Here's the culprit in active_support/multibyte/chars.rb :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
if RUBY_VERSION >= "1.9"
        # Creates a new Chars instance by wrapping _string_.
        def initialize(string)
          @wrapped_string = string
          @wrapped_string.force_encoding(Encoding::UTF_8) unless @wrapped_string.frozen?
        end

        undef <=>
      else
        def initialize(string) #:nodoc:
          @wrapped_string = string
        end
      end

It looks like the undef-ing is acting as a method proxy to allow method_missing to pass the function on to String after setting the encoding to Utf-8. But it's not working.

I tracked the error down to calling value.mb_chars on a String and then it showed up again in another spot and I gave up.

I've got work to do after all. Back to rails3 beta3 for now.

Comments

Rails 3 and Shoulda

I really want to use Rails 3 on a project that won't see a production server until at least July. So I went for it. After having to remind myself to check github for a rails3 branch on every gem I use, I only had one nemesis to defeat: Shoulda.

When you run rake test:units, shoulda says (or something similar):

.rvm/gems/ruby-1.9.1-p378/bundler/gems/shoulda-b78dbf514bbce3272023d3a4742474857c2eb3c3-rails3/lib/shoulda/autoload_macros.rb:40:in `join': can't convert # into String (TypeError)

Following some tips at RailsPlugins.org I got shoulda working. The problem happens long before your tests run. It's in the loading phase. Until our boys at thoughtbot get it working, we can work around it by manually loading shoulda with Bundler.

In test/test_helper.rb add:

1
Bundler.require(:shoulda)

And in your Gemfile, move your gem shoulda line to it's own group, like this:

1
2
3
group :shoulda do
  gem 'shoulda', :git => "git://github.com/thoughtbot/shoulda.git", :branch => "rails3"
end

Just doing those simple things got shoulda working for me. Now I have to make all my tests pass.

Comments

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.

Comments

It's OK to not be pretentious

This week I got bit by Flickraw getting banned. Because setting up your own API key in Flickraw is lame, a lot of people ended up using the internal one.

I had a few sites doing just that. But flickraw breaking made me re-evaluate why I was using it. In the past I've done a lot of "cool" things simply because it was fun or even because it was more difficult.

But doing something just because it's more difficult doesn't make me a better developer, it just makes me pretentious. I'm now using the Flickr badge with some modified css. It took way less time and loads faster.

Comments

Snippet #1

Here's a quick snippet for making something draggable and resizeable in jQuery (like my beard!).


$('#beard').draggable().resizeable();

WRONG

This "works" but gives unexpected behavior. Flipping the order you chain the calls results in weird behavior as well.

Because resizeable adds a wrapper div to any object you make resizeable, the dragging gets spotty and/or the area of movement gets constrained.

So you have to play nice with the inserted wrapper:

1
2
$('#beard').resizable();
$('#beard').parent('.ui-wrapper').draggable();

I'll leave error cases for you.

Comments

I Need Closure

This morning I was reading in the new Pickaxe, mostly looking for tidbits of Ruby 1.9 glory.

On page 67 I found one of the best and most concise definitions of a closure.

For comparison, here's the first paragraph on closure from Wikipedia:

"In computer science, a closure is a first-class function with free variables that are bound in the lexical environment. Such a function is said to be "closed over" its free variables. A closure is defined within the scope of its free variables, and the extent of those variables is at least as long as the lifetime of the closure itself. The explicit use of closures is associated with functional programming and with languages such as ML and Lisp. Closures are used to implement continuation passing style, and in this manner, hide state. Constructs such as objects and control structures can thus be implemented with closures."

Wow there's a lot of links in there. Here's Dave Thomas' page 67 definition:

closure
variables in the surrounding scope that are referenced in a block remain accessible for the life of that block and the life of any Proc object created from that block.

It reminded me of something a college professor of mine said. That closures were like a sack that you threw a method and some variables into. You could carry that sack around and wherever you opened it, that method would use the variables in the sack.

He also said that electrons in a transistor were like putting a box of puppies in a corner.

Comments

The Good and Bad of Github

The Good:

I once thought, "I need a sweet Twitter syntax highlighter". I went to github.com and I searched.

The second result looked promising. I did a gem install, added an include and Bam! it was perfect.

The Bad:

I once thought, "I should write a sweet Twitter syntax highlighter and put it on Github. That would be fun." But it's already there, and it's good. I'd probably rip some of the features out but now I have no excuse to write one.

Comments

Fun with Beards, or at least mine

I wouldn't normally put up a picture of myself, not because I'm humble or scared of being vain, but because I usually hate the way my smile turns out.

But then I thought, "Wouldn't it be fun to mess around with a beard?" So the beard is draggable and resizable and you can upload a picture of yourself.

Go waste some time.

Comments