<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Thomas Mango</title>
  <link href="http://thomasmango.com/atom.xml" rel="self"/>
  <link href="http://thomasmango.com/"/>
  <updated>2020-03-29T20:35:02+00:00</updated>
  <id>http://thomasmango.com</id>
  <author>
    <name>Thomas Mango</name>
    <email>tsmango@gmail.com</email>
  </author>

  
    <entry>
      <title>How I Keep Limited Run Running</title>
      <link href="http://thomasmango.com/2014/02/21/how-i-keep-limited-run-running"/>
      <updated>2014-02-21T00:00:00+00:00</updated>
      <id>http://thomasmango.com/2014/02/21/how-i-keep-limited-run-running</id>
      <content type="html">&lt;p&gt;&lt;em&gt;A little less than three years ago, I wrote a post that talked about how I kept our web services running, while being the only developer and operations person in our company. Since then, the amount of traffic we handle has increased more than 3000%, our revenue has grown over 5000%, and this topic is more important than ever.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;And yes, I’m still our only developer and operations person.&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;background&quot;&gt;Background&lt;/h2&gt;

&lt;p&gt;I’m Tom, and I’m half of &lt;a href=&quot;http://limitedrun.com&quot;&gt;Limited Run&lt;/a&gt;, &lt;a href=&quot;http://cardincluded.com&quot;&gt;Card Included&lt;/a&gt;, and a few other things. I also organize most of the &lt;a href=&quot;http://railsrumble.com&quot;&gt;Rails Rumble&lt;/a&gt;, but that’s a seasonal thing.&lt;/p&gt;

&lt;p&gt;For our consumer facing services, I’m the only developer and the only operations person. Having an actual work-life balance while in this role has taken a serious amount of time to develop, but that’s for another post. This post is about how I manage to keep our services, specifically Limited Run, up and running. While some services’ availability is less critical than others, Limited Run is a self-serve store platform. We have customers all over the world. These store owners must have the ability to work on their store 24 hours a day, 7 days a week, 365 days a year. Additionally, every second one of their customers cannot visit their store or make a purchase, is money they’re losing. It doesn’t matter to our customers or our customers’ customers, that I’m out to dinner, or at a baseball game, or asleep at 3 am. If something should happen, it needs to be fixed as quickly as possible.&lt;/p&gt;

&lt;p&gt;In companies with a larger staff than ours and similar availability requirements, on-call schedules help to ease the situation. Further, operations people spread out across the world help to keep everyone sane. We’re not in that situation, so we’ve built an enormous number of automated systems, checks, and fail-safes over the years to ensure we can keep everything operating as smoothly as possible. However, simply having more employees available to resolve issues, is no excuse for not doing everything possible to fortify your infrastructure.&lt;/p&gt;

&lt;p&gt;There are three important areas I focus on to keep things running smoothly: monitoring, automation, and on-the-go preparedness. Here’s how I approach each of them.&lt;/p&gt;

&lt;h2 id=&quot;monitoring&quot;&gt;Monitoring&lt;/h2&gt;

&lt;p&gt;Without thorough monitoring, you absolutely cannot expect to be able to keep your service operating. I use and seriously endorse the following services to help with monitoring:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.honeybadger.io&quot;&gt;Honeybadger&lt;/a&gt; - If your application isn’t configured to notify you of errors, just stop reading right now and go set something up. There is just no excuse for that. We used to rely on email notifications directly from our application for this, and that served us well for a while. That is, until we ran into an issue with some dkim signing logic that prevented email notifications - even those for errors - from being delivered. So, we went with Honeybadger to handle notifying us of errors, and haven’t looked back.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://getclicky.com&quot;&gt;Clicky&lt;/a&gt; - This is a fantastic, realtime analytics service. Not only does it offer everything you’d expect from a Google Analytics type service, but statistics come in as they occur. Clicky will tell you approximately how many people are currently on your site and, with Spy, will even let you see every action as it happens. If you aren’t using a realtime analytics service like this, you’re flying blind. The benefit of knowing exactly what’s going on, at any given time, is immeasurable.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://pingdom.com&quot;&gt;Pingdom&lt;/a&gt; - On it’s own, Pingdom is extremely useful. Get an email, SMS, or push notification if your site goes down. An uptime monitor like Pingdom is essential if you want to know when there is a service disruption.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://aws.amazon.com/cloudwatch&quot;&gt;Amazon CloudWatch&lt;/a&gt; - We are heavy users of and believers in Amazon Web Services. Their CloudWatch service is essential for not only automation (see below), but monitoring as well. We’ve configured various triggers, mostly related to anomalies, that will send us email notifications that can be acted upon in different ways.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://pagerduty.com&quot;&gt;PagerDuty&lt;/a&gt; - Email notifications are well and good, but at some point, they may become just noise. It’s important to separate the most important notifications, such as those from Pingdom, and bring them to your attention no matter where you are or what time of day it is. That’s where PagerDuty comes in. Additionally, I’m a heavy sleeper, so Pingdom downtime emails are not enough for me in the middle of the night. With just Pingdom, you may still find yourself worrying. However, if you couple Pingdom with PagerDuty, you will never worry again. PagerDuty will call your cellphone within seconds of receiving an email from an uptime monitor, like Pingdom. Knowing that you aren’t missing downtime notifications is extremely comforting. I recommend using this sparingly, for only the most important things, like downtime notifications. Also, as an iOS user that loves scheduled Do Not Disturb so my phone doesn’t constantly buzz from emails all night, adding PagerDuty’s alert phone number to my favorites and only allowing phone calls from those contacts while in Do Not Disturb, can’t be beat.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://support.twitter.com/articles/129550-managing-your-mobile-notification-preferences&quot;&gt;Twitter&lt;/a&gt; - A lesser known feature of Twitter is their SMS and Push Notification delivery of individual tweets (called “Mobile Notifications”). I subscribe to &lt;a href=&quot;https://twitter.com/pagerdutyops&quot;&gt;@PagerDutyOps&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/Cloud_Status&quot;&gt;@Cloud_Status&lt;/a&gt;’s Mobile Notifications so that I know when PagerDuty and AWS are having their own problems. We rely on these services to ensure our services stay up, but sometimes shit hits the fan for them too. Stay informed.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://newrelic.com&quot;&gt;New Relic&lt;/a&gt; - New Relic is like analytics for your application, rather than your traffic. Together with CloudWatch, I use New Relic to track down performance regressions and determine where the bottlenecks are. The faster your application is, especially in the places that are hit hardest under heavy load, the easier time you’ll have scaling and better handling traffic surges. New Relic was critical for us during a major refactoring of our entire cart and checkout process late last year, which both became magnitudes less resource intensive.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://sprint.ly&quot;&gt;Sprint.ly&lt;/a&gt; - While not strictly related to keeping our services running, we rely heavily on Sprint.ly for organizing and planning our day-to-day development efforts.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In addition to paid services, we’ve found it necessary to build a number of custom services to help keep an eye on various things. Here are just a few services that get run via cronjobs:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Clickylert - This is a little script that polls Clicky for the number of people currently on our sites and detects significant, upward changes. When a large spike is detected, Clickylert emails me how many people are currently on the site along with how the traffic changed over the past hour. Additionally, Clickylert can be configured to send an email to PagerDuty, which would call my phone. If Pingdom is how I get notified when something very bad happens, Clickylert is what notifies me when something out of the ordinary is happening, which may or may not lead to something bad. Over the years, our scale has grown so much and our infrastructure has improved even more so, that Clickylert is no longer configured to call me. We have massive stores running on Limited Run sending waves and waves of traffic at all hours of the day and night. It simply became easier to handle huge influxes of traffic out of nowhere, than to worry about spikes in traffic.&lt;/li&gt;
  &lt;li&gt;EC2 Instance Watcher - A few years ago, we had an issue that resulted in runaway EC2 instance replacements. This was a costly mistake, as you pay for a minimum of one hour for each instance, even if that instance was only booted for a couple of minutes. This script will deliver notifications, first by email, then to PagerDuty if things get really out of hand, whenever our instance count (running + terminated) goes above the range we normally expect it to be in. Nowadays, you can configure EC2 auto scaling groups to automatically email you on every event (which I highly suggest), so this script isn’t quite as useful as it once was.&lt;/li&gt;
  &lt;li&gt;Backlog Job Watcher - A while back, we had an issue that prevented our background jobs from being properly run. Everything from email notifications to processing lossless audio albums halted for a few hours. This script checks our backlog of jobs every so often and ensures it doesn’t get too long. If it does, it contacts me.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One other important thing we do is use &lt;a href=&quot;http://godrb.com/&quot;&gt;god&lt;/a&gt; (there are more modern alternatives, but this is simple and has worked well for us for many years) to ensure various services continue running on each of our servers. We use god to ensure HAProxy, Nginx, Apache, and our background workers continue running. We also have a cronjob that starts god every so often in case it dies, which does happen. Just like subscribing to push notifications about PagerDuty’s and Amazon’s status, layering your monitoring is important. Things may fail, but multiple failures at once are much less likely.&lt;/p&gt;

&lt;h2 id=&quot;architecture--automation&quot;&gt;Architecture &amp;amp; Automation&lt;/h2&gt;

&lt;p&gt;Invest in your architecture. Not necessarily with money directly, but with time. The more of your architecture you can automate and depend on, the better you’ll sleep at night and the more quickly you’ll be able to recover if something goes wrong. It seems like an obvious point, but I think a lot of people don’t take this seriously enough at first. If monitoring will get you half the way, self configuring server instances and auto scaling will get you the rest of the way. Being a solo developer is not an excuse to not invest time in automation. In fact, being a solo developer is even more of a reason to invest the time.&lt;/p&gt;

&lt;p&gt;I’m a big believer in &lt;a href=&quot;http://aws.amazon.com&quot;&gt;Amazon Web Services&lt;/a&gt;. As someone who was never really great at server administration, AWS has really helped me wrap my head around a lot of concepts and has given me a great place to experiment with configuring and running various systems. If you’re the only developer of your web service and don’t want to or can’t pay for a fully managed service like Heroku, you’re going to eventually have to learn to configure and fix things. AWS is a great place to learn and practice because you can spin up as many fresh, clean installs of a server instance as you need to get things right and it won’t cost more than a few dollars.&lt;/p&gt;

&lt;p&gt;Going further than just using AWS directly for testing, there have been a ton of recent advancements in automated server configuration. I personally use &lt;a href=&quot;http://www.ansible.com/home&quot;&gt;Ansible&lt;/a&gt; for our entire infrastructure, but there are other alternatives like &lt;a href=&quot;http://www.getchef.com/&quot;&gt;Chef&lt;/a&gt;, &lt;a href=&quot;http://puppetlabs.com/&quot;&gt;Puppet&lt;/a&gt;, and &lt;a href=&quot;http://aws.amazon.com/opsworks/&quot;&gt;Amazon OpsWorks&lt;/a&gt;. I cannot stress enough how important &lt;a href=&quot;http://www.vagrantup.com/&quot;&gt;Vagrant&lt;/a&gt; and automation software like Ansible is to building out your infrastructure. Pick one, learn it, and use it.&lt;/p&gt;

&lt;p&gt;I use Ansible to develop and configure our base machines, but I then turn each into a self configuring &lt;a href=&quot;http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AMIs.html&quot;&gt;AMI&lt;/a&gt;. When an instance launches, it pulls down the latest configuration files for the role it’s going to play, checks out any code that needs to be run and connects itself to the rest of the infrastructure. When you combine self configuring EC2 instances with AWS’ &lt;a href=&quot;http://aws.amazon.com/autoscaling&quot;&gt;auto scaling&lt;/a&gt; and &lt;a href=&quot;http://aws.amazon.com/elasticloadbalancing&quot;&gt;load balancing&lt;/a&gt; (or with your own custom load balancers, like we do), you’ve already gone a long way in ensuring your service stays up and running. When most people hear “auto scaling”, they think about when you get a rush of traffic and you automatically fire up additional server instances to keep up. Although that’s a main benefit of auto scaling, another benefit is simply keeping your service online. If an instance dies for some reason, a new instance can automatically start up and take its place. Additionally, having all of your instances behind a load balancer (even just a single instance), means that application servers can come and go without affecting connectivity to your service.&lt;/p&gt;

&lt;p&gt;To take the idea of auto scaling further, you have to design your systems to be loosely coupled. For most web services, if you remove data from the equation (into &lt;a href=&quot;http://aws.amazon.com/rds&quot;&gt;Amazon RDS&lt;/a&gt;, for example), you’re simply left with processing. For Limited Run, we use a combination of RDS, S3, background queues, and EC2 instances that can be turned on and off at any time, without affecting anything. When you can think of EC2 instances running your web application as disposable processing servers, auto scaling is no longer just about adjusting for traffic, it’s about keeping your service online, no matter what happens.&lt;/p&gt;

&lt;p&gt;One final piece of the infrastructure puzzle, is redundancy. Being an AWS user, we leverage RDS’s Multi-AZ support, which places a slave of our main database in another availability zone. Additionally, we run EC2 instances across multiple availability zones, and have Route 53 configured with failovers to backup load balancers in various availability zones. Whatever your specific setup is, the main point is that taking out a single server, or every server in a single availability zone, shouldn’t cause you any problems. Okay, there may be a brief minute or so issue when things failover, but you aren’t left scrambling to fix things. As much as possible, things should be fixing themselves.&lt;/p&gt;

&lt;h2 id=&quot;on-the-go-preparedness&quot;&gt;On-The-Go Preparedness&lt;/h2&gt;

&lt;p&gt;Over the years, as our monitoring, automation, and infrastructure has improved, I’ve become much less dependent on having to be prepared to deal with an issue while away from home (where my main office is). Additionally, while I may run web services, and work on software all day, I’m actually not that into technology when I leave the house. For me, as I get closer and closer to 30, part of that work-life balance I mentioned earlier, means being able to step away from technology, or at least, not have it in my face all the time. Having said that, I don’t go anywhere without, at the very least, my phone. But if I’m going out for the entire day, I will generally throw a bag in my car that also has an iPad and MacBook Air in it, just in case. Also worth noting, my iPhone is on AT&amp;amp;T and my iPad is on Verizon. Cell coverage isn’t amazing where I live, so being able to tether on either network, is nice.&lt;/p&gt;

&lt;p&gt;On my iPhone and iPad, I have have access to the following apps:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://panic.com/prompt/&quot;&gt;Prompt&lt;/a&gt; - A really nice SSH application from &lt;a href=&quot;http://panic.com&quot;&gt;Panic&lt;/a&gt; that works on iPhones and iPads.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.edovia.com/screens&quot;&gt;Screens&lt;/a&gt; - A fantastic VNC application. Screens will get me into a machine in my home office, letting me do whatever I need to do from a development environment. This is more of a last resort.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In addition to these, I also have apps for the &lt;a href=&quot;http://aws.amazon.com/console/mobile/&quot;&gt;AWS Console&lt;/a&gt;, PagerDuty, New Relic, and Pingdom, but rarely use them. If I have my iPad with me and need access to the AWS Console, I end up just using the website, which works great.&lt;/p&gt;

&lt;p&gt;Again, this is all just a final safety net in case automated systems don’t resolve something that arises while I’m out. The goal is to not need to rely on these things, but if something does come up, it can be resolved from my phone. Having an iPad or a laptop with me can sometimes speed things up in certain circumstances, but generally isn’t necessary.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Werner Vogel, Amazon’s CTO, famously said: &lt;a href=&quot;https://www.google.com/#q=%22everything+fails%2C+all+the+time%22&quot;&gt;“everything fails, all the time”&lt;/a&gt;. You need to design for failure and you need to be ready to react when something goes wrong. For me, as a single developer, that means thorough monitoring, being able to rely on an automated architecture, and always being connected.&lt;/p&gt;
</content>
    </entry>
  
    <entry>
      <title>Custom Error Pages, AWS's ELB, and Route 53 Failover</title>
      <link href="http://thomasmango.com/2013/08/28/aws-elb-route-53-custom-error-pages"/>
      <updated>2013-08-28T00:00:00+00:00</updated>
      <id>http://thomasmango.com/2013/08/28/aws-elb-route-53-custom-error-pages</id>
      <content type="html">&lt;p&gt;There has been a thread on the AWS support forums since July 25th, 2011, calling for AWS to &lt;a href=&quot;https://forums.aws.amazon.com/thread.jspa?threadID=72363&quot;&gt;add customizable error pages&lt;/a&gt; to their &lt;a href=&quot;http://aws.amazon.com/elasticloadbalancing/&quot;&gt;ELB (Elastic Load Balancer)&lt;/a&gt; product.&lt;/p&gt;

&lt;p&gt;AWS recently added health check and failover features to their &lt;a href=&quot;http://aws.amazon.com/route53/&quot;&gt;Route 53 (DNS)&lt;/a&gt; product, and now some people are wondering whether or not this removes the need for custom error pages on Elastic Load Balancers:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;strong&gt;Nalog wrote:&lt;/strong&gt; What about using &lt;a href=&quot;http://aws.amazon.com/route53/faqs/#dns_failover_does_dns_failover_su&quot;&gt;DNS Failover on ELB&lt;/a&gt;?
&lt;/blockquote&gt;

&lt;p&gt;Short answer, no, it doesn't.&lt;/p&gt;

&lt;h2&gt;Long Answer:&lt;/h2&gt;

&lt;p&gt;Using &lt;a href=&quot;http://docs.aws.amazon.com/Route53/latest/DeveloperGuide/dns-failover.html&quot;&gt;Route 53's DNS failover&lt;/a&gt;, while similar, is unfortunately not the same thing. With a DNS failover setup, clients would wait the TTL (probably 60 seconds in this case) before re-requesting DNS entries for the request (thus getting a failover IP address). However, Route 53 won't failover until some amount of time passes and it believes that the ELB should be failed over from. So you may be in the 2 minute range at this point.&lt;/p&gt;

&lt;p&gt;During this 2 minute or so range, blank pages are being served to clients from the ELB. Additionally, clients (browsers) aren't always great about handling transitions between the blank pages from ELB requests and some failover, say a static site being hosted out of S3. Even with no-cache headers, and updated DNS entries because of the failover, browsers will often cache the results and not show updated pages (due to a failover or recovery) by simply clicking the refresh button. Restarting the browser generally forces a refresh of the page, but end users aren't going to expect to have to do that, nor should they have to.&lt;/p&gt;

&lt;p&gt;If ELB was able to serve a custom error page, rather than a blank response, when no instance responded to a request, this would solve all of the above issues. Clients wouldn't need to wait for new DNS records, nor would they be affected by cached pages. They would simply receive the error page as the response of their intended request. If they refresh and the ELB can return a real response, they'd display the real response.&lt;/p&gt;

&lt;p&gt;If AWS ever adds the ability to have an ELB respond with a custom error page when no instance responds to a request, it will most likely work like a standard &lt;a href=&quot;http://www.haproxy.org&quot;&gt;HAProxy&lt;/a&gt; setup. With HAProxy, you can configure a &quot;backup&quot; instance. For example, you can configure a backend like:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/tsmango/6365452.js?file=haproxy&quot;&gt; &lt;/script&gt;
&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;backend my-web-app
  server service-unavailable 127.0.0.1:8000 weight 1 backup
  server i-eb1c5083 10.154.148.222:80 weight 1 check
  server i-f41c531e 10.141.158.72:80 weight 1 check

listen my-web-http
  bind :80
  default_backend my-web-app&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;

&lt;p&gt;In this scenario, you configure HAProxy with a backend that has 2 real instances and then you also run Apache on port 8000 on the same instance running HAProxy. If neither real instance can respond to a request, HAProxy automatically routes the request to 127.0.0.1:8000 and you would configure Apache to rewrite every request and respond with your error page.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/tsmango/6365452.js?file=apache&quot;&gt; &lt;/script&gt;
&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;&lt;VirtualHost *:8000&gt;
  ServerAlias *

  DocumentRoot /var/www/
  &lt;Directory /var/www/&gt;
    Options FollowSymLinks
    AllowOverride None
    Order allow,deny
    Allow from all
  &lt;/Directory&gt;

  RewriteEngine On

  RewriteCond %{DOCUMENT_ROOT}/503.html -f
  RewriteCond %{SCRIPT_FILENAME} !503.html
  RewriteRule ^.*$ /503.html [L]
&lt;/VirtualHost&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;

&lt;p&gt;Route 53's DNS failover is useful for some things, such as your ELB completely going away, but it isn't a substitute for ELBs being able to actually serve error pages, rather than blank responses, when your instances don't respond.&lt;/p&gt;</content>
    </entry>
  
    <entry>
      <title>Goals &amp; Routines or: How I've Lost <del>Almost 90</del> 100 Pounds</title>
      <link href="http://thomasmango.com/2013/07/02/goals-and-routines-or-how-ive-lost-almost-90-pounds"/>
      <updated>2013-07-02T00:00:00+00:00</updated>
      <id>http://thomasmango.com/2013/07/02/goals-and-routines-or-how-ive-lost-almost-90-pounds</id>
      <content type="html">&lt;p&gt;I can no longer count the number of times that I’ve started writing, deleted, and restarted this post. Although I am proud of myself for what I’ve accomplished over the past year or so, I’m embarrassed for even having a chance to accomplish it. But putting those feelings aside, maybe reading this will help someone else set a goal, and change their routine for the better.&lt;/p&gt;

&lt;h2 id=&quot;2012&quot;&gt;2012&lt;/h2&gt;

&lt;p&gt;Last year, with my 28th birthday just a few months away, I realized it was time to lose weight. A lot of weight. I kept thinking back about something I read: “once you hit 30, it’s a lot more difficult to lose weight”. I’m embarrassed to admit that, at this point in my life, I had weighed 265 pounds or so for a while. Oh sure, from time to time, maybe I’d be motivated and lose 10 pounds or so, before snapping back to my usual ways and gaining it back, but for the most part, my weight stayed roughly the same for years.&lt;/p&gt;

&lt;p&gt;If you’ve never been this overweight, it’s hard to explain. No clothing I owned fit me and I no longer remembered what it was like to be comfortable. Working from home for years, rarely going out and not really having a social life to speak of, made it easy to ignore this all. But after years of being like this and just concentrating on my work, I had gotten into this routine. And while I’m good at routines, this one just happened to be really bad for me.&lt;/p&gt;

&lt;p&gt;So it was time for change. Having tried Atkins when I was much younger, losing weight for six months only to gain even more back than I had lost, I was opposed to trying another diet of this type. In fact, I didn’t want to “go on a diet”. I wanted to change the way I lived, and perhaps foolishly, I just wanted to do this on my own. I wanted to drink less coffee, eat healthier, and most of all, eat less.&lt;/p&gt;

&lt;p&gt;In March of 2012, I put &lt;a href=&quot;http://tapbots.com/software/weightbot/&quot;&gt;Weightbot&lt;/a&gt; on my first home screen and set a goal of 250 pounds. Instead of eating a bagel with cream cheese for breakfast, despite not being hungry (I soon realized that I was never actually hungry, I just ate to eat), I ate 2 Nutri-Grain cereal bars. Instead of going to Wendy’s and getting a bacon cheeseburger and fries, I went to Wendy’s and got a salad. Instead of getting a chicken cutlet, cheese, and bacon hero with a sweetened iced tea from my favorite deli, I got a tuna melt on a whole wheat wrap and a bottle of water. Instead of getting something delicious from the restaurant around the corner, I got a chef salad. Instead of having cookies at night, I had a yogurt.&lt;/p&gt;

&lt;p&gt;I simply began substituting everything I ate with something that was healthier (even if it wasn’t that much healthier - Wendy’s salads, for example). But more than the substitution, I made a point to eat much less than I used to eat. I stopped eating everything on my plate just because it was there. I ate more slowly and tried to be more conscious about when I was actually hungry. I stopped grabbing a snack for no reason while pacing around the office thinking about how to implement a feature for &lt;a href=&quot;http://limitedrun.com&quot;&gt;Limited Run&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I was lucky in that I very quickly began to noticeably, at least to myself and Weightbot, lose weight. Seeing results is an incredible motivator. It shows that you’ve made a choice that actually made a difference. Obvious maybe, but important.&lt;/p&gt;

&lt;p&gt;I continued updating my goal, first by ten pounds at a time 240, 230, 220, then by less, 215, 210, 205. I continued to try and eat healthier and eat less. Trying to find that point when I was just full. I cut out an afternoon snack. I found that only eating one Nutri-Grain cereal bar for breakfast was satisfying. I continued to iterate on my routine and my goal, getting better each week.&lt;/p&gt;

&lt;p&gt;Oddly, I never really got into exercising. I tried, but it didn’t really stick. I didn’t feel like I was accomplishing anything and convinced myself I was still too overweight for it to matter. Deep down, I wanted to be one of those people that could run every day, but I had a goal already. I didn’t share my exact goal of 180 pounds with anyone, but that was secretly my goal and simply by getting into a new routine, I was able to make steady progress toward it. (Having an &lt;a href=&quot;http://thomasmango.com/napoleon/&quot;&gt;english bulldog&lt;/a&gt; who will only walk a third of a mile with you once every other day didn’t help either, but I guess I can’t blame him.)&lt;/p&gt;

&lt;p&gt;After nine months, I hit 182 pounds and plateaued. I was a little disappointed that I didn’t actually get down to 180 pounds, but I decided that losing 83 pounds was an impressive feat and I no longer considered myself overweight (I’m just over 6 feet tall). And if I was being honest with myself, 180 was my really just my secret, far fetched goal, that I never believed I could get close to in the first place. I was damn impressed with 182 pounds.&lt;/p&gt;

&lt;p&gt;So, it was the end of the year, I had new clothes that actually fit me (some were even too big) and most importantly, I finally felt comfortable. I felt comfortable with myself and I felt comfortable in public. I’m not ashamed to admit that it feels great when your family sees you and comments on how you lost so much weight. Or even when a complete stranger looks at the photo on your license as you’re buying something and asks if you are really the same person. It just flat out feels good. Physically and mentally, losing that weight was (and still is!) amazing.&lt;/p&gt;

&lt;h2 id=&quot;2013&quot;&gt;2013&lt;/h2&gt;

&lt;p&gt;As I wasn’t losing any additional weight and it was winter, I decided to ease up. Once or twice a week, I’d eat a bit more than I had been eating previously, or perhaps get something that I really used to enjoy eating. I must stress that, unlike before my weight loss last year, I did this consciously. I continued keeping track of my weight, although not every day, and decided I would be okay so long that I didn’t go over 190 pounds.&lt;/p&gt;

&lt;p&gt;Now, I should be clear that although I lost a lot of weight, I hadn’t been exercising and wasn’t in shape at all. Not even in the slightest. On top of that, I became (I suppose I always was?) a weakling. My 55 pound bulldog could now drag me anywhere at will. There’s no stopping him. But I did need some time to reset myself. I needed time to adjust to my new weight, and relax a bit, and enjoy being comfortable, and try and understand how to maintain my weight while keeping things balanced.&lt;/p&gt;

&lt;p&gt;The months went on. Without much effort, I gained a few pounds, lost a few pounds, gained a few pounds. In May, however, I hit that magic 190 pounds. Maybe it seems obvious to you, but only then did I realize that the only reason I was able to lose the initial weight was because I had an actual goal. I was striving for something. Toward something. So in my mind, staying &lt;strong&gt;below 190 pounds&lt;/strong&gt; was not the same kind of goal as getting &lt;strong&gt;down to 180 pounds&lt;/strong&gt;. Staying below 190, was more like an alarm. If you hit 190, it’s time to take action. It wasn’t something I could work toward.&lt;/p&gt;

&lt;p&gt;So, I hit 190 and realized staying below 190 wasn’t an actual goal. It was time to set one. Setting another weight goal wasn’t necessarily what I wanted, though. Last year I lost a lot of weight. But this year? This year I wanted to become a healthy person. I wanted to exercise. I want to turn myself into a runner. I wanted to become someone that had an ongoing routine of always being healthy, thinking about what I ate, and most importantly, about being active. I didn’t want to just sit in front of my desk all day and night writing code (although I bet our &lt;a href=&quot;http://limitedrun.com&quot;&gt;Limited Run&lt;/a&gt; customers would like that).&lt;/p&gt;

&lt;p&gt;My new realistic goal was to be someone who keeps track of their health and who could go out and enjoy running every day. My secret fantasy goal is to run a 10k (&lt;strong&gt;was&lt;/strong&gt; secret, now that I’ve told you), but in reality, I just want to keep running and be healthy. So, I bought a &lt;a href=&quot;http://www.fitbit.com/flex&quot;&gt;Fitbit Flex&lt;/a&gt; and a Couch to 10k app for my phone. I set goals in Fitbit and began tracking how many steps I took in an average day (not many), and what I ate throughout the day. I started walking and increasing my steps and started on the Couch to 10k program. So while I’m still going after a goal, I’m approaching losing weight differently now. Instead of just losing weight, I want to be healthier and keep track of what I’m eating, while I work on becoming a runner.&lt;/p&gt;

&lt;p&gt;In truth, wearing an activity tracker isn’t something I ever thought I’d do, but now that I’ve started, there’s something fascinating about wearing a Fitbit on your wrist. It’s out of the way, but you’re still conscious of it. It’s there. You know it’s there and it’s a subtle reminder that you should eat healthier and that you should be more active. Instead of parking in the closest spot at the grocery store, you park further away. Instead of taking your dog outside to the curb, you trick that lazy dude into walking a loop around the block. And while, psychologically, using a Fitbit is an incredible thing that will help you make better decisions as you start using it, eventually it just helps you get into a better overall routine. Over time, it becomes less about making conscious choices at each turn and instead lets you train yourself to always be making better, healthier choices, with less effort. Plus, as a nerd, it’s also fun. It’s fun to keep track of things and chart your progress and look at stats.&lt;/p&gt;

&lt;p&gt;After about six weeks or so of keeping track of what I eat and exercising almost every day, I’m already down below 178 pounds, and more importantly, I feel great. Running is actually fun. I look forward to it and am happy at night knowing that I went for a run that day. It’s also really rewarding being able to run longer and longer each time I go out.&lt;/p&gt;

&lt;p&gt;I’m generally a really private person. I’m embarrassed I used to be so overweight and unhealthy, but I’m really happy with how far I’ve come in just over a year and I guess I don’t really mind boasting a bit now that I’m here. And so if you want to lose weight, start exercising, or just be healthier, you should know know that, even in your late 20’s, it’s actually possible. If I can lose nearly 90 pounds, there’s no telling what you can do if you try. It just takes making attainable goals, getting into a good routine, and constantly updating your goals as you hit them.&lt;/p&gt;

&lt;p&gt;I’d love to hear from you, so please feel free to send an email to tsmango over at gmail.&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

&lt;h2 id=&quot;update-aug-31-2013&quot;&gt;Update: Aug 31, 2013&lt;/h2&gt;

&lt;p&gt;I’ve continued my progress running and eating healthy and have now dropped 100 pounds in total since March of 2012. But much more important than that number (in fact I’m now working to maintain my weight, rather than lose more), is that my usual routine has me running 5km, 6 days a week. Also, last week, I ran my first 10km (that secret fantasy goal I had just a few months ago).&lt;/p&gt;

&lt;p&gt;After all of these years, I finally feel like an active, healthy person.&lt;/p&gt;

&lt;p&gt;When I started this a year and a half ago, I never expected to be able to come so far and change my life so thoroughly, but once you get into a good routine, have seen, and &lt;strong&gt;felt&lt;/strong&gt;, real progress, it helps to further your motivation. If you’re thinking about making a change to be healthier, I really hope this post proves to you that it’s absolutely possible. Even if your work has you sitting behind a desk all day.&lt;/p&gt;
</content>
    </entry>
  
    <entry>
      <title>Getting to Know ActiveSupport::Callbacks</title>
      <link href="http://thomasmango.com/2011/09/02/getting-to-know-active-support-callbacks"/>
      <updated>2011-09-02T00:00:00+00:00</updated>
      <id>http://thomasmango.com/2011/09/02/getting-to-know-active-support-callbacks</id>
      <content type="html">&lt;p&gt;While writing &lt;a href=&quot;https://github.com/tsmango/active_configuration&quot;&gt;ActiveConfiguration&lt;/a&gt;, I needed a way to run a callback when certain methods were executed. Thankfully, ActiveSupport was already available, so I had access to &lt;a href=&quot;http://api.rubyonrails.org/classes/ActiveSupport/Callbacks.html&quot;&gt;ActiveSupport::Callbacks&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;what-is-a-callback&quot;&gt;What is a Callback?&lt;/h3&gt;

&lt;p&gt;At this point, you may be wondering what a callback even is. Simply put, a callback allows you to run some code (usually a method) automatically when another piece of code is run. In Rails, you’ll commonly see callbacks that run before, after or even around other bits of code. In fact, if you’ve ever used &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;before_create&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;after_save&lt;/code&gt; or any of the other ActiveRecord &lt;a href=&quot;http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html&quot;&gt;life cycle callbacks&lt;/a&gt;, you’ve already been using the ActiveSupport::Callbacks module, albeit indirectly and through a layer of abstraction.&lt;/p&gt;

&lt;p&gt;While those life cycle callbacks are indispensable in an ActiveRecord model, they wouldn’t help me in ActiveConfiguration. So, what if like me you want a custom callback or need callbacks in a class that isn’t an ActiveRecord model?&lt;/p&gt;

&lt;h3 id=&quot;walking-through-activeconfigurationoption&quot;&gt;Walking Through ActiveConfiguration::Option&lt;/h3&gt;

&lt;p&gt;Let’s start by looking at a simple class with three methods:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/1187700.js?file=option-0.rb&quot;&gt; &lt;/script&gt;

&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;class Option
  def default(value)
    @default_value = (value.is_a?(Symbol) ? value.to_s : value)
  end

  def format(value)
    @allowed_format = (value.is_a?(Symbol) ? value.to_s : value)
  end

  def validate!
    ...
  end
end&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;

&lt;p&gt;Here, the plan is to run the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#validate!&lt;/code&gt; method after the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#default&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#format&lt;/code&gt; methods are run. To do that, let’s first include ActiveSupport::Callbacks:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/1187700.js?file=option-1.rb&quot;&gt; &lt;/script&gt;

&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;class Option
  include ActiveSupport::Callbacks

  ...
end&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;

&lt;p&gt;Next, we’ll define a callback named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;validate&lt;/code&gt; (not to be confused with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#validate!&lt;/code&gt; method defined above - more on this later):&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/1187700.js?file=option-2.rb&quot;&gt; &lt;/script&gt;

&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;class Option
  include ActiveSupport::Callbacks

  define_callbacks :validate

  ...
end&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;

&lt;p&gt;After defining a new callback named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;validate&lt;/code&gt;, we’ll use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;set_callback&lt;/code&gt; to actually set a callback up to run:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/1187700.js?file=option-3.rb&quot;&gt; &lt;/script&gt;

&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;class Option
  include ActiveSupport::Callbacks

  define_callbacks :validate

  set_callback :validate, :after, :validate!

  ...
end&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;

&lt;p&gt;When using ActiveSupport::Callbacks, I think &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#set_callback&lt;/code&gt; may be a source of confusion for some people. Unfortunately, by showing a complicated example with a subclass in addition to using the same name for both the callback itself as well as the method to be run, the &lt;a href=&quot;http://api.rubyonrails.org/classes/ActiveSupport/Callbacks.html&quot;&gt;documentation&lt;/a&gt; doesn’t help to make it any easier.&lt;/p&gt;

&lt;p&gt;Admittedly, my validate example isn’t much better. Here, the callback is named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;validate&lt;/code&gt; and the method that I want to be run when the callback fires is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;validate!&lt;/code&gt; - a subtle, but important distinction.&lt;/p&gt;

&lt;p&gt;So, what exactly are we passing to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#set_callback&lt;/code&gt;?&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;The &lt;em&gt;name&lt;/em&gt; of the callback we used in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;define_callbacks&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;When&lt;/em&gt; the method should be run in relation to the callback being defined &lt;sup id=&quot;fnr-1&quot;&gt;&lt;a href=&quot;#fn-1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/li&gt;
  &lt;li&gt;The &lt;em&gt;method&lt;/em&gt; to execute when the callback fires.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The way I remember what &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;set_callback&lt;/code&gt; means is by reading it backwards:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“&lt;em&gt;Execute the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;validate!&lt;/code&gt; method &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;after&lt;/code&gt; the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;validate&lt;/code&gt; callback is fired.&lt;/em&gt;”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;putting-it-all-together&quot;&gt;Putting It All Together&lt;/h3&gt;

&lt;p&gt;Up to this point, we’ve only defined what should happen &lt;em&gt;when&lt;/em&gt; the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;validate&lt;/code&gt; callback fires. We’ve yet to specify when the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;validate&lt;/code&gt; callback actually &lt;em&gt;should&lt;/em&gt; be fired.&lt;/p&gt;

&lt;p&gt;To do that, we’ll use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#run_callbacks&lt;/code&gt; method:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/1187700.js?file=option.rb&quot;&gt; &lt;/script&gt;

&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;class Option
  include ActiveSupport::Callbacks

  define_callbacks :validate

  set_callback :validate, :after, :validate!

  def default(value)
    run_callbacks :validate do
      @default_value = (value.is_a?(Symbol) ? value.to_s : value)
    end
  end

  def format(value)
    run_callbacks :validate do
      @allowed_format = (value.is_a?(Symbol) ? value.to_s : value)
    end
  end

  ...

  def validate!
    ...
  end
end&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;

&lt;p&gt;(For the unabridged version of ActiveConfiguration::Option, see the &lt;a href=&quot;https://github.com/tsmango/active_configuration/blob/v1.0.0/lib/active_configuration/option.rb&quot;&gt;source on GitHub&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;That’s really all there is to it when looking to add custom callbacks to your own classes. By wrapping your code in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#run_callbacks&lt;/code&gt;, any callbacks you’ve setup to run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;before&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;after&lt;/code&gt; or even &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;around&lt;/code&gt;, will be executed at the correct time.&lt;/p&gt;

&lt;h3 id=&quot;life-cycle-callbacks-in-activerecord&quot;&gt;Life Cycle Callbacks in ActiveRecord&lt;/h3&gt;

&lt;p&gt;Fair warning, things start to get a bit more hairy from here on out, so if you’re just interested in using callbacks in your own class, feel free to skip the rest of this article. But if you’d like to dive into Rails a bit, keep reading.&lt;/p&gt;

&lt;p&gt;As I mentioned earlier, ActiveRecord supports a number of &lt;a href=&quot;http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html&quot;&gt;life cycle callbacks&lt;/a&gt; that are extremely useful. These callbacks are actually defined using ActiveSupport::Callbacks under the hood and after looking at the example above, we should be able to figure out how that’s being done.&lt;/p&gt;

&lt;p&gt;First, let’s look at the &lt;a href=&quot;https://github.com/rails/rails/blob/v3.1.0/activerecord/lib/active_record/callbacks.rb&quot;&gt;ActiveRecord::Callbacks module&lt;/a&gt;:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/1187700.js?file=active-record-callbacks.rb&quot;&gt; &lt;/script&gt;

&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;require 'active_support/core_ext/array/wrap'

module ActiveRecord

  module Callbacks
    extend ActiveSupport::Concern

    CALLBACKS = [
      :after_initialize, :after_find, :after_touch, :before_validation, :after_validation,
      :before_save, :around_save, :after_save, :before_create, :around_create,
      :after_create, :before_update, :around_update, :after_update,
      :before_destroy, :around_destroy, :after_destroy, :after_commit, :after_rollback
    ]

    included do
      extend ActiveModel::Callbacks
      include ActiveModel::Validations::Callbacks

      define_model_callbacks :initialize, :find, :touch, :only =&amp;gt; :after
      define_model_callbacks :save, :create, :update, :destroy
    end

    def destroy #:nodoc:
      run_callbacks(:destroy) { super }
    end

    def touch(*) #:nodoc:
      run_callbacks(:touch) { super }
    end

  private

    def create_or_update #:nodoc:
      run_callbacks(:save) { super }
    end

    def create #:nodoc:
      run_callbacks(:create) { super }
    end

    def update(*) #:nodoc:
      run_callbacks(:update) { super }
    end
  end
end&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;

&lt;p&gt;Some of this should be familiar to you. First you’ll notice that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ActiveModel::Callbacks&lt;/code&gt; is being extended, so we’ll want to look at that in a moment. Next, you’ll see two calls to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;define_model_callbacks&lt;/code&gt; and multiple mentions of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;run_callbacks&lt;/code&gt;, which we used earlier in our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#default&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#format&lt;/code&gt; methods.&lt;/p&gt;

&lt;p&gt;Let’s pick out just one of the methods above to focus on, say &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;create_or_update&lt;/code&gt;:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/1187700.js?file=active-record-callbacks-0.rb&quot;&gt; &lt;/script&gt;

&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;def create_or_update
  run_callbacks(:save) { super }
end&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;

&lt;p&gt;This method is overriding AR’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#create_or_update&lt;/code&gt; method and wrapping a call to the existing method (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;super&lt;/code&gt;) with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;run_callbacks(:save)&lt;/code&gt;. From what we learned earlier, we know this means that any callbacks to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;save&lt;/code&gt; should be fired here.&lt;/p&gt;

&lt;p&gt;But, this doesn’t tell the entire story. We haven’t seen a call to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;set_callback&lt;/code&gt; yet which we know is necessary to actually hook a method up to a callback.&lt;/p&gt;

&lt;p&gt;To get to the bottom of this implementation, let’s venture into &lt;a href=&quot;https://github.com/rails/rails/blob/v3.1.0/activemodel/lib/active_model/callbacks.rb&quot;&gt;ActiveModel::Callbacks&lt;/a&gt;:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/1187700.js?file=active-model-callbacks.rb&quot;&gt; &lt;/script&gt;

&lt;p&gt;I admit, this may look a little scary, but let’s go through it a piece at a time.&lt;/p&gt;

&lt;p&gt;First, our faithful ActiveSupport::Callbacks is included:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/1187700.js?file=active-model-callbacks-0.rb&quot;&gt; &lt;/script&gt;

&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;def self.extended(base)
  base.class_eval do
    include ActiveSupport::Callbacks
  end
end&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;

&lt;p&gt;Next, we see &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;define_model_callbacks&lt;/code&gt;, which was called in ActiveRecord::Callbacks:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/1187897.js?file=active-model-callbacks-1.rb&quot;&gt; &lt;/script&gt;

&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;def define_model_callbacks(*callbacks)
  options = callbacks.extract_options!
  options = {
     :terminator =&amp;gt; &amp;quot;result == false&amp;quot;,
     :scope =&amp;gt; [:kind, :name],
     :only =&amp;gt; [:before, :around, :after]
  }.merge(options)

  types   = Array.wrap(options.delete(:only))

  callbacks.each do |callback|
    define_callbacks(callback, options)

    types.each do |type|
      send(&amp;quot;_define_#{type}_model_callback&amp;quot;, self, callback)
    end
  end
end&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;

&lt;p&gt;If you’ve ever gone spelunking in the Rails source before, the beginning of that method where options are being extracted should look familiar, otherwise, let’s not worry about it.&lt;/p&gt;

&lt;p&gt;The more relevant part to this discuss is when the array of callbacks is iterated over. For each callback, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;define_callbacks&lt;/code&gt; (the method we used earlier) is called. This means callbacks are defined from those specified back in ActiveRecord::Callbacks such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:initialize&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:find&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:touch&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:save&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:create&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:update&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:destroy&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Additionally, after specifying each callback, the allowed types (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;before&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;after&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;around&lt;/code&gt;) are iterated over and the actual callback methods are defined.&lt;/p&gt;

&lt;p&gt;Let’s just take one example. One of the callbacks defined was &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;save&lt;/code&gt;. For this callback, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;send(&quot;_define_#{type}_model_callback&quot;, self, callback)&lt;/code&gt; would be called three times (once for each of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;before&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;after&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;around&lt;/code&gt;). Looking further down the implementation, we’ll see the three methods being called:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/1187897.js?file=active-model-callbacks-2.rb&quot;&gt; &lt;/script&gt;

&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;def _define_before_model_callback(klass, callback) #:nodoc:
  klass.class_eval &amp;lt;&amp;lt;-CALLBACK, __FILE__, __LINE__ + 1
    def self.before_#{callback}(*args, &amp;amp;block)
      set_callback(:#{callback}, :before, *args, &amp;amp;block)
    end
  CALLBACK
end

def _define_around_model_callback(klass, callback) #:nodoc:
  klass.class_eval &amp;lt;&amp;lt;-CALLBACK, __FILE__, __LINE__ + 1
    def self.around_#{callback}(*args, &amp;amp;block)
      set_callback(:#{callback}, :around, *args, &amp;amp;block)
    end
  CALLBACK
end

def _define_after_model_callback(klass, callback) #:nodoc:
  klass.class_eval &amp;lt;&amp;lt;-CALLBACK, __FILE__, __LINE__ + 1
    def self.after_#{callback}(*args, &amp;amp;block)
      options = args.extract_options!
      options[:prepend] = true
      options[:if] = Array.wrap(options[:if]) &amp;lt;&amp;lt; &amp;quot;!halted &amp;amp;&amp;amp; value != false&amp;quot;
      set_callback(:#{callback}, :after, *(args &amp;lt;&amp;lt; options), &amp;amp;block)
    end
  CALLBACK
end&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;

&lt;p&gt;If you look at the first method, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_define_before_model_callback&lt;/code&gt;, you’ll see that a class method is being dynamically defined for the callback given (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;save&lt;/code&gt;). So, this call to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_define_before_model_callback&lt;/code&gt; will define the method &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;before_save&lt;/code&gt; and make it available for you to use in your ActiveRecord model, like so:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/1187897.js?file=post.rb&quot;&gt; &lt;/script&gt;

&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;class Post &amp;lt; ActiveRecord::Base
  before_save :generate_slug

  def generate_slug
    self.title = self.title.mb_chars.normalize(:kd).gsub(/[^\x00-\x7F]/n, '').to_s.gsub(/[']+/, '').gsub(/\W+/, ' ').strip.downcase.gsub!(' ', '-')
  end
end&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;

&lt;p&gt;Now, if you look again at the the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;before_save&lt;/code&gt; method that was defined from within &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_define_before_model_callback&lt;/code&gt;, you’ll see a call to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;set_callback&lt;/code&gt;. This means that a method you pass to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;before_save&lt;/code&gt; will be passed into the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;set_callback&lt;/code&gt; method and will be executed &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;before&lt;/code&gt; the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;save&lt;/code&gt; callback.&lt;/p&gt;

&lt;p&gt;Looking back to ActiveRecord::Callback, you’ll remember the following method:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/1187700.js?file=active-record-callbacks-0.rb&quot;&gt; &lt;/script&gt;

&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;def create_or_update
  run_callbacks(:save) { super }
end&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;

&lt;p&gt;This means that the method passed to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;before_save&lt;/code&gt; in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Post&lt;/code&gt; class above is set as a callback method to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;save&lt;/code&gt; callback and before the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#create_or_update&lt;/code&gt; method is run, the callback method you set will be executed.&lt;/p&gt;

&lt;h3 id=&quot;final-thoughts&quot;&gt;Final Thoughts&lt;/h3&gt;

&lt;p&gt;When used thoughtfully, ActiveSupport::Callbacks can be very helpful and I think this example of how Rails uses the underlying module to expose specific life cycle callback methods to ActiveRecord models is fascinating. And really, this module is just one of the many excellent things you’ll find in the Rails codebase. So while it may feel overwhelming to try and understand the entire Rails source all at once, taking an example like this where you look at a specific method and peel back the layers of how it’s implemented can be very approachable and can lead to understanding and reusing some great code that’s already available to you.&lt;/p&gt;

&lt;p&gt;If you have any feedback, please feel free to send me an email. I’d love to hear from you.&lt;/p&gt;

&lt;hr /&gt;

&lt;ol&gt;
&lt;li id=&quot;fn-1&quot;&gt;This can either be &lt;code&gt;before&lt;/code&gt;, &lt;code&gt;after&lt;/code&gt; or &lt;code&gt;around&lt;/code&gt;. &lt;a href=&quot;#fnr-1&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content>
    </entry>
  
    <entry>
      <title>ActiveConfiguration: A Generic Settings Store</title>
      <link href="http://thomasmango.com/2011/08/30/active-configuration-a-generic-settings-store"/>
      <updated>2011-08-30T00:00:00+00:00</updated>
      <id>http://thomasmango.com/2011/08/30/active-configuration-a-generic-settings-store</id>
      <content type="html">&lt;p&gt;&lt;a href=&quot;http://github.com/tsmango/active_configuration&quot;&gt;ActiveConfiguration&lt;/a&gt; is a Rails engine that exposes a generic settings store to ActiveRecord models. Made for very configurable applications, it allows you to avoid implementing specific ways to store settings for each model that needs such a configuration. If your application isn’t very configurable, ActiveConfiguration isn’t what you want.&lt;/p&gt;

&lt;p&gt;For example, if your application had a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Category&lt;/code&gt; model that only had a configurable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sort&lt;/code&gt; attribute, ActiveConfiguration would be overkill. Rather, you would just read and write values using a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sort&lt;/code&gt; column and restrict the allowed values using something like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;validates_inclusion_of&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;However, if your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Category&lt;/code&gt; model was more flexible in its configuration, you may want a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sort&lt;/code&gt; setting, a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;limit&lt;/code&gt; setting and multiple &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;price_filter&lt;/code&gt; settings that can be configured by your end user. Without ActiveConfiguration, you would have to develop a way to store and validate these settings for this specific scenario. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sort&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;limit&lt;/code&gt; settings are simple but because &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;price_filter&lt;/code&gt; can accept multiple rules, you’d have to set up an additional model. Still, this isn’t really an issue when you’re dealing with just a single configurable model. When you’re dealing with many, things tend to get messy.&lt;/p&gt;

&lt;p&gt;With ActiveConfiguration, all of your settings, even for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;price_filter&lt;/code&gt;, can be stored in a generic way. ActiveConfiguration provides a place to store settings for each of your models and even handles validation when you restrict the allowed values or format of an option.&lt;/p&gt;

&lt;h3 id=&quot;source&quot;&gt;Source&lt;/h3&gt;

&lt;p&gt;The source for ActiveConfiguration is &lt;a href=&quot;http://github.com/tsmango/active_configuration&quot;&gt;available at GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;installation&quot;&gt;Installation&lt;/h3&gt;

&lt;p&gt;Add the following to your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Gemfile&lt;/code&gt;:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/1182604.js?file=install-gem.rb&quot;&gt; &lt;/script&gt;

&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;gem 'active_configuration'&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;

&lt;p&gt;Generate the migration for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;settings&lt;/code&gt; table:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/1182604.js?file=generate.rb&quot;&gt; &lt;/script&gt;

&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;rails g active_configuration:install&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;

&lt;p&gt;Migrate your database:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/1182604.js?file=migrate.rb&quot;&gt; &lt;/script&gt;

&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;rake db:migrate&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;

&lt;h3 id=&quot;example-configuration&quot;&gt;Example Configuration&lt;/h3&gt;

&lt;script src=&quot;https://gist.github.com/1182604.js?file=category.rb&quot;&gt; &lt;/script&gt;

&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;class Category &amp;lt; ActiveRecord::Base
  configure do
    option :sort do
      default  'alphabetical'
      restrict 'alphabetical', 'manual'
    end

    option :limit do
      format 'fixnum'
    end

    option :price_filter do
      format    'float'
      modifiers 'eq', 'lt', 'gt', 'lte', 'gte'
      multiple  true
    end
  end
end&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;

&lt;p&gt;After installing ActiveConfiguration, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#configure&lt;/code&gt; block is available to
every ActiveRecord model. If the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#configure&lt;/code&gt; block is defined with a valid
configuration, additional methods are made available on the model.&lt;/p&gt;

&lt;h3 id=&quot;example-usage&quot;&gt;Example Usage&lt;/h3&gt;

&lt;script src=&quot;https://gist.github.com/1182604.js?file=example.rb&quot;&gt; &lt;/script&gt;

&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt; category = Category.create(:name =&amp;gt; 'Vinyl Records')
=&amp;gt; #&amp;lt;Category id: 1, name: &amp;quot;Vinyl Records&amp;quot;, created_at: &amp;quot;2011-08-03 15:46:11&amp;quot;, updated_at: &amp;quot;2011-08-03 15:46:11&amp;quot;&amp;gt;

?&amp;gt; category.settings
=&amp;gt; #&amp;lt;ActiveConfiguration::SettingManager:0x10e7d1950 @configurable=#&amp;lt;Category id: 1, name: &amp;quot;Vinyl Records&amp;quot;, created_at: &amp;quot;2011-08-03 15:46:11&amp;quot;, updated_at: &amp;quot;2011-08-03 15:46:11&amp;quot;&amp;gt;&amp;gt;

?&amp;gt; category.settings[:sort]
=&amp;gt; {:value=&amp;gt;&amp;quot;alphabetical&amp;quot;, :modifier=&amp;gt;nil}

?&amp;gt; category.settings[:sort][:value]
=&amp;gt; &amp;quot;alphabetical&amp;quot;

?&amp;gt; category.settings[:sort][:value] = 'manual'
=&amp;gt; &amp;quot;manual&amp;quot;

?&amp;gt; category.settings[:price_filter]
=&amp;gt; []

?&amp;gt; category.settings[:price_filter] = [{:modifier =&amp;gt; 'gt', :value =&amp;gt; 10.00}, {:modifier =&amp;gt; 'lte', :value =&amp;gt; 25.00}]
=&amp;gt; [{:value=&amp;gt;10.0, :modifier=&amp;gt;&amp;quot;gt&amp;quot;}, {:value=&amp;gt;25.0, :modifier=&amp;gt;&amp;quot;lte&amp;quot;}]

?&amp;gt; category.save
=&amp;gt; true

?&amp;gt; category.settings[:sort][:value]
=&amp;gt; &amp;quot;manual&amp;quot;

?&amp;gt; category.settings[:price_filter]
=&amp;gt; [{:value=&amp;gt;10.0, :modifier=&amp;gt;&amp;quot;gt&amp;quot;}, {:value=&amp;gt;25.0, :modifier=&amp;gt;&amp;quot;lte&amp;quot;}]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;

&lt;h3 id=&quot;additional-notes&quot;&gt;Additional Notes&lt;/h3&gt;

&lt;p&gt;I accept that ActiveConfiguration’s concept is a bit out there, but I’ve found it very useful in certain circumstances and hope that others find it useful as well. I think the &lt;a href=&quot;https://github.com/tsmango/active_configuration&quot;&gt;README&lt;/a&gt; provides all of the information necessary to get started using this gem, but there are additional details in the &lt;a href=&quot;http://rdoc.info/github/tsmango/active_configuration/master/frames&quot;&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you have any questions or feedback, I’d love to hear from you. Please feel free to email me or &lt;a href=&quot;https://github.com/tsmango/active_configuration/issues&quot;&gt;open an issue&lt;/a&gt; at GitHub.&lt;/p&gt;
</content>
    </entry>
  
    <entry>
      <title>Generated by Jekyll &amp; Open Source Plugins</title>
      <link href="http://thomasmango.com/2011/08/26/generated-by-jekyll-and-open-source-plugins"/>
      <updated>2011-08-26T00:00:00+00:00</updated>
      <id>http://thomasmango.com/2011/08/26/generated-by-jekyll-and-open-source-plugins</id>
      <content type="html">&lt;p&gt;I’ve spent my free time over the past week replacing my existing site with this new, &lt;a href=&quot;https://github.com/mojombo/jekyll&quot;&gt;Jekyll&lt;/a&gt; generated site and I couldn’t be happier with how it came out. Jekyll, written by GitHub’s &lt;a href=&quot;https://github.com/mojombo&quot;&gt;Tom Preston-Werner&lt;/a&gt;, is an extremely extendible static site generator. While developing my new site, which is hosted in an S3 bucket on Amazon, I ended up implementing a couple of simple plugins that I’ve opened sourced in hopes that others may find them useful. If you’d like to see the entire source of this site, check out the &lt;a href=&quot;https://github.com/tsmango/thomasmango.com&quot;&gt;GitHub repository&lt;/a&gt; and if you’d like to learn more about my plugins, keep reading.&lt;/p&gt;

&lt;h3 id=&quot;aliasgenerator&quot;&gt;AliasGenerator&lt;/h3&gt;

&lt;p&gt;This generator looks through the YAML Front Matter of each post and generates redirect pages when an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;alias&lt;/code&gt; configuration is set. I found this plugin necessary when migrating my existing posts on tumblr to a more sane url structure.&lt;/p&gt;

&lt;p&gt;Example Configuration:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/1174145.js?file=example-configuration.html&quot;&gt; &lt;/script&gt;

&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;---
  layout: post
  title: &amp;quot;How I Keep Limited Pressing Running&amp;quot;
  alias: /post/6301645915/how-i-keep-limited-pressing-running/index.html
---&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;

&lt;p&gt;This alias is set on my &lt;a href=&quot;http://thomasmango.com/2011/06/07/how-i-keep-limited-pressing-running/&quot;&gt;“How I Keep Limited Pressing Running”&lt;/a&gt; article which was originally published at tumblr and will redirect anyone going to the old address.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/tsmango/jekyll_alias_generator&quot;&gt;View the source at GitHub →&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;flickrsettag&quot;&gt;FlickrSetTag&lt;/h3&gt;

&lt;p&gt;This tag generates a simple image gallery from a set of photos on Flickr.&lt;/p&gt;

&lt;p&gt;Example Usage:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/1174155.js?file=example-usage.html&quot;&gt; &lt;/script&gt;

&lt;p&gt;This will result in a bit of generated html displaying thumbnails of each photo in the set. Check the repository’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;README&lt;/code&gt; for configuration details.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/tsmango/jekyll_flickr_set_tag&quot;&gt;View the source at GitHub →&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;more-about-plugins&quot;&gt;More About Plugins&lt;/h3&gt;

&lt;p&gt;Although there are a decent amount of &lt;a href=&quot;https://github.com/mojombo/jekyll/wiki/Plugins&quot;&gt;plugins already available&lt;/a&gt; for Jekyll, like me, you may not find the exact plugin to suit your needs. Luckily, Jekyll makes it pretty straightforward to write your own. I highly suggest picking out a few interesting plugins and reading through the source and understanding how they work.&lt;/p&gt;
</content>
    </entry>
  
    <entry>
      <title>How I Keep Limited Pressing Running</title>
      <link href="http://thomasmango.com/2011/06/07/how-i-keep-limited-pressing-running"/>
      <updated>2011-06-07T00:00:00+00:00</updated>
      <id>http://thomasmango.com/2011/06/07/how-i-keep-limited-pressing-running</id>
      <content type="html">&lt;meta http-equiv=&quot;refresh&quot; content=&quot;0;url=/2014/02/21/how-i-keep-limited-run-running/&quot; /&gt;</content>
    </entry>
  
    <entry>
      <title>Splitting a Large Rails Application in Three</title>
      <link href="http://thomasmango.com/2011/05/06/splitting-a-large-rails-application-in-three"/>
      <updated>2011-05-06T00:00:00+00:00</updated>
      <id>http://thomasmango.com/2011/05/06/splitting-a-large-rails-application-in-three</id>
      <content type="html">&lt;p&gt;After weeks of planning and a month of development, we finally split &lt;a href=&quot;http://limitedpresing.com&quot;&gt;Limited Pressing&lt;/a&gt;’s free auction, trading and collecting services out into a separate site last week. Although I have been involved in a couple of “big rewrites” before, this project was the most complicated I’ve ever done. It’s one thing to rewrite a large, internal application or an entertainment application, but Limited Pressing is a large e-commerce platform that people depend on. People are constantly buying and selling things, so downtime had to be minimized and everything really had to go just right.&lt;/p&gt;

&lt;h3 id=&quot;a-brief-history-of-limited-pressing&quot;&gt;A Brief History of Limited Pressing&lt;/h3&gt;

&lt;p&gt;Before going into details about splitting the application itself, I should back up and briefly explain how Limited Pressing evolved over time. LP, an e-commerce platform catering to the music industry, has been in development for about two years. The original idea was to be something of an eBay alternative for independent music. We had three major points we wanted to hit: auctions, trading and stores. We launched first with auctions and trading and immediately went to work on stores, the only feature we were going to charge for.&lt;/p&gt;

&lt;h3 id=&quot;the-need-to-separate-stores--community&quot;&gt;The Need to Separate Stores &amp;amp; Community&lt;/h3&gt;

&lt;p&gt;After releasing stores to the general public, we began to get a lot of interest in them. We had solved a lot of issues people had with other store platforms and provided a great set of features specific to labels, bands and musicians. Unfortunately, it became clear that our free auction and trading services were distracting from our stores service. A lot of people were confused as to if we were a store platform or a community marketplace. We tried to be both for a while, but these two aspects clashed more and more. Additionally, users of the free services didn’t really want to be bothered with stores and it was hard for people looking for a store to make it past our other services.&lt;/p&gt;

&lt;p&gt;In the end, we decided that for both aspects to be as good as they could be, we had to move our free auction and trading services out into a separate site completely. This new site is called &lt;a href=&quot;http://www.theoldlp.com&quot;&gt;The Old LP&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;extracting-authentication--being-an-oauth-provider&quot;&gt;Extracting Authentication &amp;amp; Being an OAuth Provider&lt;/h3&gt;

&lt;p&gt;Luckily, there was very little overlap between stores and community features. There were a few low level utilities related to currency and region support and then there was our user and authentication system, but otherwise, things could be clearly separated. Without this minimal overlap, we may never have be able to go down this road.&lt;/p&gt;

&lt;p&gt;The first thing I did was duplicate the codebase into a new application. I then began to delete every controller, model and view that had nothing to do with that application. I removed auctions, deals, collections, messages, etc. from Limited Pressing and I removed stores and all store related features from the new application, The Old LP.&lt;/p&gt;

&lt;p&gt;After removing features, I completely tore out the authentication systems, which was built on top of Authlogic. Like many Rails developers, I was lured into using a bloated authentication system. I’ve tried a number of them including &lt;a href=&quot;https://github.com/binarylogic/authlogic&quot;&gt;Authlogic&lt;/a&gt; and &lt;a href=&quot;https://github.com/plataformatec/devise&quot;&gt;Devise&lt;/a&gt;. Unfortunately in my experience, I feel like these authentication systems always end up either being overkill or requiring too much overriding and customization that it makes no sense to bother using them. Because one of our requirements was to have the same logins across both applications, I took this as a chance to get rid of Authlogic. I ripped it all out and started building another application, called &lt;a href=&quot;http://multipass.limitedpressing.com&quot;&gt;Multipass&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Multipass is my favorite part of this project. Very simply, Multipass started with the Limited Pressing database. I removed every table, except the users table and then removed all application specific columns from the users table and boiled it down to just user accounts. My inspiration for Multipass was &lt;a href=&quot;http://37signals.com/accounts&quot;&gt;37signal Accounts&lt;/a&gt;: a secure single sign on service that works across all of our applications.&lt;/p&gt;

&lt;p&gt;I’m not sure how 37signals went about doing cross application authentication through their accounts system, but with Multipass, I decided to make it an OAuth provider. To make this happen, I started with &lt;a href=&quot;https://github.com/pelle/oauth-plugin&quot;&gt;oauth-plugin&lt;/a&gt;. This is a fantastic library, but there were a few things I wanted to avoid, which meant I had to make a number of changes to what oauth-plugin gives you by default.&lt;/p&gt;

&lt;p&gt;For now, I disabled the ability for non-administrator’s to create client applications. Although we don’t currently want anyone to be able to create an OAuth Client Application and use our login system on their own, this is something we may allow in the future. We have a lot of Limited Pressing IDs and there may be other music related sites and services that would find it useful to piggy back on our authentication system at some point.&lt;/p&gt;

&lt;p&gt;The bigger change was that we didn’t want users to have to &lt;em&gt;allow&lt;/em&gt; access to their account when signing into Limited Pressing or The Old LP (or any future application of ours). Although the idea of granting access to your account has become more mainstream because of Twitter and Facebook, I don’t think everyone gets it yet. It’s confusing and scary for people who don’t understand what’s going on.&lt;/p&gt;

&lt;p&gt;I decided to implement a similar authentication flow to Twitter’s “Sign in with Twitter” &lt;a href=&quot;http://dev.twitter.com/pages/sign_in_with_twitter&quot;&gt;/oauth/authenticate&lt;/a&gt; flow. Normally, every time a user attempts to log into a client application, that user would have to &lt;em&gt;allow&lt;/em&gt; the third party application to use your account - this is how oauth-plugin works by default. However, “Sign in with Twitter” only requires a user to allow the third party application once. All subsequent logins skip the allow / deny process and send the user right back to the third party client. I achieved this by first modifying the generated RequestToken model. Rather than always generating a new access token on every sign in (oauth-plugin’s default), I now first check if a valid token exists for that user and client application. If one does exist, I return that and skip right over the allow / deny request.&lt;/p&gt;

&lt;p&gt;Although this helped a lot in that users wouldn’t have to re-allow every time they signed in, this wasn’t good enough. I already know that Limited Pressing, The Old LP and any other applications of ours are trustworthy, so why should I ask the user to grant access to the account? I modified my new /oauth/authenticate style flow further to detect whether or not the client application that’s requesting access was trusted or not (I define a trusted application as one that was created by and tied to an administrator). If the application is trusted, not only do I skip all subsequent  allow / deny requests when a valid access token already exists, but I even skip the initial request when a new access token needs to be generated and I automatically allow access.&lt;/p&gt;

&lt;p&gt;By implementing the concept of trusted applications in addition to the Twitter style “Sign in with Twitter” authentication flow, this allows Limited Pressing and The Old LP to send a user off to Multipass for authentication, but does not require that user to specifically grant access to our trusted applications. If we end up allowing third parties to create client applications in the future, they will not be inherently trusted and will require the user to allow the request for access.&lt;/p&gt;

&lt;p&gt;On the client side of things, I wrote a custom OAuth based strategy for the excellent &lt;a href=&quot;https://github.com/intridea/omniauth&quot;&gt;OmniAuth&lt;/a&gt; gem. This allowed me to quickly and easily tie into our Multipass authentication system. I then removed duplicate user fields from the client applications and wrote a plugin to automatically pull fields that exist in Multipass accounts from Multipass directly. That means if you load up an instance of a User model in Limited Pressing and call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;first_name&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;last_name&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;email_addreess&lt;/code&gt;, etc., those calls automatically pass through that User and hook back into Multipass for the current values. This means not only are we not duplicating data across applications, but all existing code in each application that called those values on user objects wouldn’t have to be changed. Additionally, all objects in each application still point to the local users table and use those ids for foreign keys, but every user also has a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uid&lt;/code&gt; that represents the associated Multipass user.&lt;/p&gt;

&lt;p&gt;By turning Multipass into an OAuth provider, not only do we now have a secure, single sign on system that can be used across all of our current and future related web applications, but we also now have a proper authentication system that can be used for a possible, future API.&lt;/p&gt;

&lt;h3 id=&quot;maintainability--our-support-system&quot;&gt;Maintainability &amp;amp; Our Support System&lt;/h3&gt;

&lt;p&gt;Aside from the business related decisions in splitting Limited Pressing into two services, there were also benefits in terms of future maintainability. Limited Pressing’s codebase is roughly 2 years old and it had numerous customer facing features, in addition to authentication, administration tools and our custom help and support system.&lt;/p&gt;

&lt;p&gt;With the launch of The Old LP, I removed authentication from the mix and built Multipass. However, our custom help and support system&lt;sup id=&quot;fnr-1&quot;&gt;&lt;a href=&quot;#fn-1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; is still baked right into Limited Pressing. I plan to continue down the path of reducing the complexity of each application by moving our support system into it’s own, separate application.&lt;/p&gt;

&lt;p&gt;Looking past the obvious benefits of smaller, more focused codebases, splitting up Limited Pressing has other advantages. First, our services are now decoupled from each other. If our store platform does not depend on our auction system, something affecting our auction system will no longer affect our store platform. Next, breaking LP up makes it easier to upgrade everything to Rails 3 in pieces. Limited Pressing and The Old LP are still running on Rails 2.3.11, but Multipass is a Rails 3 application and when removed from LP, our support system will also be running on Rails 3. I will be able to upgrade LP and TOLP to Rails 3, individually, as time permits.&lt;/p&gt;

&lt;h3 id=&quot;final-thoughts&quot;&gt;Final Thoughts&lt;/h3&gt;

&lt;p&gt;Although this was a big undertaking, a lot of the work was in planning, testing and deployment of the three resulting applications. I ran through tests in all three systems and audited every bit of code to ensure everything would continue working properly after being separated. I spent days developing and rehearsing a deployment strategy. I took snapshots from our production database and wrote a detailed plan for our period of scheduled maintenance. During maintenance the three new applications would be deployed with their databases starting as duplicates of the production LP database. Each database was then stripped down to the necessary tables and modified to support changes to that specific application. I even timed myself and figured out what operations could be done at the same time to shorten the maintenance window. For example, I ended up deploying each application while restoring and migrating the next, depending application’s database to minimize downtime.&lt;/p&gt;

&lt;p&gt;But in the end, despite all of my planning, there were still some bugs that made it into production - something I knew could not be avoided no matter how much preparation was done. I spent the day of our deployment putting out minor fires here and there. And now that a week has passed and I can reflect on the entire project, I’m incredibly relieved it’s over, but also extremely excited about our newly de-coupled applications. It was absolutely worth the effort.&lt;/p&gt;

&lt;hr /&gt;

&lt;ol&gt;
&lt;li id=&quot;fn-1&quot;&gt;This is essentially a custom built support system, like &lt;a href=&quot;http://tenderapp.com&quot;&gt;Tender Support&lt;/a&gt;, only less polished. At some point we may just move to Tender, but for now, this works for us and only had an upfront cost of a weekend or so to build. &lt;a href=&quot;#fnr-1&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content>
    </entry>
  
    <entry>
      <title>Changing the Conversation</title>
      <link href="http://thomasmango.com/2011/05/06/changing-the-conversation"/>
      <updated>2011-05-06T00:00:00+00:00</updated>
      <id>http://thomasmango.com/2011/05/06/changing-the-conversation</id>
      <content type="html">&lt;p&gt;We have a very easy to use digital sales system on &lt;a href=&quot;http://limitedpressing.com&quot;&gt;Limited Pressing&lt;/a&gt;. You create a product in your store and if you want to attach a digital download to that product, you upload a file and then purchase credits (either in batches of 125, 400 or 1000). Whenever someone orders that product from you, they get to download the file.&lt;/p&gt;

&lt;p&gt;Back when we rolled out our &lt;a href=&quot;http://blog.thomasmango.com/post/1493591618/a-support-system-that-doesnt-hurt&quot;&gt;new support system&lt;/a&gt;, we thought it was a great opportunity to collect and review the most common questions we received. After a few weeks, we figured we could create help documents based on the questions we’d been asked. As it turns out, one of the biggest questions was whether or not digital credits could be used across multiple products. If you purchased 1000 credits on one product, could you use those credits on all of your products? To everyone’s disappointment, the answer is no.&lt;/p&gt;

&lt;p&gt;We have a valid reason for doing things this way: it costs us money to store your files. We can’t let you buy 1000 credits and upload 1000 albums. We’d go broke, Limited Pressing would shut down and you’d be stuck selling your digital goods from somewhere else that’s way more expensive. Neither of us wants that.&lt;/p&gt;

&lt;p&gt;My co-founder (and brother), &lt;a href=&quot;http://nickmango.com&quot;&gt;Nick&lt;/a&gt;, suggested we make a single change to combat this issue: stop using the word “credit” and instead use the word “download”. The problem is that when people hear the word “credit” they think of a bank. They think of a big stockpile that they can grab from whenever they need it. We decided to make the change to our marketing pages, in our product editor where you purchase the “downloads” and when we speak to customers about setting up digital downloads. Incredibly, this simple change to how we talk about and describe our digital system, resulted in us &lt;em&gt;never&lt;/em&gt; receiving another question about whether “downloads” could be used across multiple products.&lt;/p&gt;

&lt;p&gt;Sometimes you need to change the way you do things in your application to make it more clear to your users what’s going on and other times you just need to change the conversation.&lt;/p&gt;
</content>
    </entry>
  
    <entry>
      <title>Resque and Very Fast Jobs [Spoiler: Avoid Them!]</title>
      <link href="http://thomasmango.com/2010/11/18/resque-and-very-fast-jobs-spoiler-avoid-them"/>
      <updated>2010-11-18T00:00:00+00:00</updated>
      <id>http://thomasmango.com/2010/11/18/resque-and-very-fast-jobs-spoiler-avoid-them</id>
      <content type="html">&lt;p&gt;Although I suspect most people using Resque already know to avoid this, I thought I would write about an experience I had with Resque earlier this week in the hope that someone will benefit from what I learned.&lt;/p&gt;

&lt;h3 id=&quot;background&quot;&gt;Background&lt;/h3&gt;

&lt;p&gt;We recently launched version 2.0 of &lt;a href=&quot;http://thomasmango.com/projects/firefly&quot;&gt;Firefly&lt;/a&gt; (my day job). With 2.0, came a completely re-written backend revolving around Twitter’s new &lt;a href=&quot;http://dev.twitter.com/pages/site_streams&quot;&gt;Site Streams API&lt;/a&gt;. Firefly 2.0 is focused on seeing where your friends are. It does this by collecting tweets with location information (including geo tagged tweets, tweets with photos that are geo tagged and third party check-in service tweets like Foursquare, Gowalla and many others). Once you sign into Firefly’s iPhone app or website, you’re added to one of our available Site Streams and we start receiving and processing your &lt;a href=&quot;http://dev.twitter.com/doc/get/statuses/home_timeline&quot;&gt;home_timeline&lt;/a&gt; in addition to various other messages that come through a Site Stream connection.&lt;/p&gt;

&lt;h3 id=&quot;backlog&quot;&gt;Backlog&lt;/h3&gt;

&lt;p&gt;A very important thing to remember when working with any of Twitter’s streaming APIs is that you must read from the stream as quickly as possible. If you don’t read the stream fast enough, your connection will be terminated. If your connection keeps getting terminated because you aren’t reading fast enough, they may block your access. With this in mind, I decided to use our existing Resque background processing setup. I took every item that came through the site stream and queued it up to be processed by a Resque worker later. I figured, “most of these items we ignore so the job will just happen instantly and it won’t be a big deal, plus we get to read from the stream instantly because we aren’t doing any work inline”. If you’re shaking your head right now, you already know where this is going.&lt;/p&gt;

&lt;p&gt;Here’s what I naively forgot to consider: the length of time it takes to process a job != the amount of time it takes to process the logic you wrote inside of that job. What’s missing from the equation? &lt;strong&gt;The overhead in processing the job!&lt;/strong&gt; It takes time for a Resque worker to start and stop processing a job and as it turns out, it takes enough time that when we hit a certain threshold of active users on Firefly, our queue started growing in size at an insane rate.&lt;/p&gt;

&lt;p class=&quot;image&quot;&gt;
  &lt;a href=&quot;http://thomasmango.com/images/2010/11/resque-jobs.png&quot;&gt;
    &lt;img src=&quot;http://thomasmango.com/images/2010/11/resque-jobs.png&quot; /&gt;
  &lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;We peaked at close to 60k jobs in the queue before I could shut our Site Stream connections down, start investigating the issue and work on a fix.&lt;/p&gt;

&lt;h3 id=&quot;solution&quot;&gt;Solution&lt;/h3&gt;

&lt;p&gt;When I realized what was going on, it turned out that there was an obvious fix: reduce the number of unnecessary jobs being queued into Resque. Because of the nature of Firefly, we only end up processing a small subset of tweets (ones that we can collect location information on). Almost every other tweet and streaming message just gets passed over and these are the streaming items we don’t want to queue to be processed later. The key to doing this is to remember that these streaming items still need to be processed as fast as possible to avoid slowing down the reading of the Site Stream connections.&lt;/p&gt;

&lt;p&gt;First, I ensured that we never went to the database when determining whether or not a streaming item was something we wanted to queue. Next, I wrote a set of rules, specific to Firefly, that would recognize and reject any streaming item we didn’t care about. And lastly, I ordered the rules so that the the fastest to process were first (each rule can reject a streaming item so if the most expensive rules were last, we always spend the least amount of time to reject an item).&lt;/p&gt;

&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;If a job will run so fast that it can be executed inline, don’t queue it. It’s that simple. Just be conscious of every job you’re creating.&lt;/p&gt;

&lt;p&gt;It’s embarrassing to admit that I let this through to production, but I did. The important thing is that I learned to be very aware of how long a job is really going to take and whether or not it’s worth it to queue it in the first place. I also learned that I need to start monitoring queue size and setup notifications if the queue continues to grow in size, but that’s a story for another day.&lt;/p&gt;
</content>
    </entry>
  
    <entry>
      <title>A Support System That Doesn't Hurt</title>
      <link href="http://thomasmango.com/2010/11/06/a-support-system-that-doesnt-hurt"/>
      <updated>2010-11-06T00:00:00+00:00</updated>
      <id>http://thomasmango.com/2010/11/06/a-support-system-that-doesnt-hurt</id>
      <content type="html">&lt;p&gt;We opened &lt;a href=&quot;http://limitedpressing.com&quot;&gt;Limited Pressing&lt;/a&gt; to the public a year ago and up until last week, we’ve been accepting support requests to an email address we provided on the site as well as a public forum. As our traffic grew, handling support requests this way became unbearable. Often, a request involves some discussion internally before responding. To do this, we’d forward the email to each other to discuss it and when we replied, we’d CC each other. It was tiresome and unwieldily. It was also easy to lose track of who we were talking to because we didn’t have any context, just an email address.&lt;/p&gt;

&lt;p&gt;Well, that changed last weekend. We said enough was enough. We talked for a few minutes Sunday morning about what we wanted out of a support system and by 10pm the public forum was gone, the support email address had an auto responder and we had a brand new support system in place. And what I find most interesting about the whole thing is that we’ve had more support requests this week than any previous week in the past year. Thankfully, every one of those requests was a pleasure to deal with because of the new system.&lt;/p&gt;

&lt;h3 id=&quot;requirements&quot;&gt;Requirements&lt;/h3&gt;

&lt;p&gt;When designing the new support system, we had a few must haves:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The word “tickets” is too technical for most people.&lt;/li&gt;
  &lt;li&gt;You shouldn’t need an account to submit a support request.&lt;/li&gt;
  &lt;li&gt;You should receive email notifications to confirm we received your request and whenever there’s an update to your request.&lt;/li&gt;
  &lt;li&gt;Staff members should receive email notifications whenever someone submits a request and whenever a request is updated by someone else.&lt;/li&gt;
  &lt;li&gt;Staff members should be able to have an internal, private discussion right on that support request’s page. Context is everything.&lt;/li&gt;
  &lt;li&gt;Each support request should have as much information we know about the person asking the question so staff members don’t have to hunt around for it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There were a lot of other ideas we threw around that would have been neat, but not worth the time. For example, it would be nice to know when other staff members were currently looking at (or typing a response to) the same support request you were looking at. It would be useful, but we wanted to get the new support system up and running as quickly as possible and this just didn’t make the cut.&lt;/p&gt;

&lt;p&gt;Another feature that didn’t make it in was the ability for a staff member to assign a question to another staff member. A formal system would be nice, but since we could leave staff only notes on each support request, the same basic thing could be handled without a separate feature.&lt;/p&gt;

&lt;p&gt;Frequently asked questions and response templates are a couple of other features we were thinking about implementing. We may still implement these, but were they necessary on the first iteration? Definitely not.&lt;/p&gt;

&lt;h3 id=&quot;12-hours-later&quot;&gt;12 Hours Later&lt;/h3&gt;

&lt;p&gt;The system ended up being extremely simple and did exactly what we needed.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Users, whether they’re logged in or not, ask us questions.&lt;/li&gt;
  &lt;li&gt;Every question has a unique URL that isn’t guessable. The URLs aren’t completely secure, but they’re “secure enough”.&lt;/li&gt;
  &lt;li&gt;Staff members can have a conversation about the question right on the question page.&lt;/li&gt;
  &lt;li&gt;Everyone gets notified when there’s something new to see.&lt;/li&gt;
  &lt;li&gt;Questions automatically change state between Open, Pending and Solved depending on who answers what and when.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;more-support-requests-than-ever-before&quot;&gt;More Support Requests Than Ever Before&lt;/h3&gt;

&lt;p&gt;With our old setup, an open support email address and a public forum, we received a decent amount of support requests. When moving to the new question system, we setup an auto responder on the support email address that pointed people to the new system and we completely removed the forums. The result? Within 12 hours, people started using the new system. No instructions, no anything. We’ve had about 5x our usual load of support requests with the new setup this week and we’ve spent about 1/4 of the time handling them. The new setup is a complete success.&lt;/p&gt;

&lt;p&gt;So why the sudden interest in Limited Pressing support? I have a theory. A lot of people feel like they’re being a bother emailing a support email address, so they just don’t. And the support forums? People don’t want to ask personal questions on a public forum and people don’t want to ask questions they think may make them look stupid on a public forum. People don’t want to be a bother and don’t want to look stupid. It’s that simple. Our private questions area solved both of these issues.&lt;/p&gt;

&lt;p&gt;Additionally, we wanted our support system to feel friendly. Rather than “creating a support ticket”, you “ask a question”. Here’s what the ask a question form looks like:&lt;/p&gt;

&lt;p class=&quot;image&quot;&gt;
  &lt;a href=&quot;http://thomasmango.com/images/2010/11/new-question.png&quot;&gt;
    &lt;img src=&quot;http://thomasmango.com/images/2010/11/new-question.png&quot; /&gt;
  &lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;It’s a minor difference that I think changes how people approach it. It’s easy to ask a question. It’s more of a commitment to “open a new support ticket”.&lt;/p&gt;

&lt;p&gt;Also, unlike support emails and forum topics, questions don’t require subjects. Instead, you choose from a list of several general categories:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;I have a question before getting a store.&lt;/li&gt;
  &lt;li&gt;I’d like to request a new feature.&lt;/li&gt;
  &lt;li&gt;I’m confused about how something works.&lt;/li&gt;
  &lt;li&gt;I think something is broken.&lt;/li&gt;
  &lt;li&gt;Other.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;Without narrowing the scope of the project, I would have spent too long building the new support system and it would have included a ton of bells and whistles we didn’t need. It just wouldn’t have been worth it. With the narrowed scope, I only invested a single day and we still ended up with a vastly improved way to manage support requests.&lt;/p&gt;

&lt;p&gt;Always reduce a project’s scope as much as you can and see how it works in production. You can add things later if you really need to, but if you’re lucky, you won’t.&lt;/p&gt;
</content>
    </entry>
  
    <entry>
      <title>Experimenting with #newtwitter</title>
      <link href="http://thomasmango.com/2010/11/02/experimenting-with-newtwitter"/>
      <updated>2010-11-02T00:00:00+00:00</updated>
      <id>http://thomasmango.com/2010/11/02/experimenting-with-newtwitter</id>
      <content type="html">&lt;p&gt;When Twitter recently launched their new site, &lt;a href=&quot;http://twitter.com/newtwitter&quot;&gt;#newtwitter&lt;/a&gt;, I was delighted to learn it was actually an API client. As someone who builds web applications and works on APIs myself, it was inspirational to see this all done with HTML and Javascript. Needless to say, when my account gained access to #newtwitter, I fired up my Web Inspector and started digging around with the console – you can learn a lot with the console’s tab completion.&lt;/p&gt;

&lt;p&gt;After experimenting for a bit, I whipped up some quick Javascript that appends a “?” link to each trend. When clicking the “?” link, a standard #newtwitter dialog opens up and an explanation of the trend, fetched from &lt;a href=&quot;http://whatthetrend.com&quot;&gt;What The Trend&lt;/a&gt;, is displayed.&lt;/p&gt;

&lt;p class=&quot;image&quot;&gt;
  &lt;img src=&quot;http://thomasmango.com/images/2010/11/trend-explanation.png&quot; /&gt;
&lt;/p&gt;

&lt;p&gt;One interesting thing to remember when working with the trends list on #newtwitter is that trends update every once in a while. Simply executing this script once won’t do the trick. I decided to let jQuery’s &lt;a href=&quot;http://api.jquery.com/live/&quot;&gt;live&lt;/a&gt; function handle that issue.&lt;/p&gt;

&lt;p&gt;Check out the source below if you’re interested in how I did it:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/660636.js?file=trends-explained.js&quot;&gt; &lt;/script&gt;

&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;jQuery(function(){
  var TrendExplanation = {
    dialog:null,
    trend:null,

    // Open a dialog with the explanation of the given trend.
    open:function(trend) {
      this.dialog = new twttr.widget.Dialog({draggable: true});
      this.trend = trend;

      this.setup().explain();
    },

    // Set the dialog's title and show it.
    setup:function() {
      this.dialog.$title.html('About &amp;amp;quot;' + TrendExplanation.trend + '&amp;amp;quot;');
      this.dialog.$find('.twttr-dialog-content').html('&amp;lt;p&amp;gt;Loading...&amp;lt;/p&amp;gt;');
      this.dialog.show();

      return this;
    },

    // Fetch an explanation for this TrendExplanation's current trend.
    explain:function() {
      $.ajax({
        url: 'http://www.whatthetrend.com/api/trend/getByName/' + encodeURIComponent(TrendExplanation.trend) + '/jsonp?callback=',
        dataType: 'jsonp',
        success: function(data) {
          if(data['api']['trend'] &amp;amp;&amp;amp; data['api']['trend']['blurb']['text'] != '') {
            TrendExplanation.update(data['api']['trend']['blurb']['text']);
          } else {
            TrendExplanation.update('Unable to find details about that trend.');
          }
        },
        error:function(data) {
          TrendExplanation.update('There was a problem attempting to find details about that trend.');
        }
      });

      return this;
    },

    // Update the dialog for this TrendExplanation with the given explanation.
    update:function(explanation) {
      this.dialog.$find('.twttr-dialog-content').html('&amp;lt;p style=&amp;quot;margin-top:5px;&amp;quot;&amp;gt;' + explanation + '&amp;lt;/p&amp;gt;');
      this.dialog.$find('.twttr-dialog-content').append(footer);

      return this;
    },

    // Hide this TrendExplanation's dialog.
    hide:function() {
      this.dialog.hide();

      return this;
    }
  };

  // When moving over this trend-item, show the explain-trend link.
  // If a Trend doesn't have an explain-trend link, add one.
  $('.trend-item').live('mouseover', function(index) {
    if($(this).find('.explain-trend').length == 0) {
      $(this).append($(&amp;quot;&amp;lt;a/&amp;gt;&amp;quot;, {
        &amp;quot;href&amp;quot;:   &amp;quot;http://whatthetrend.com/trend/&amp;quot; + encodeURIComponent($(this).find('.trend-link').text()),
        &amp;quot;class&amp;quot;:  &amp;quot;explain-trend&amp;quot;,
        &amp;quot;target&amp;quot;: &amp;quot;_blank&amp;quot;,
        &amp;quot;text&amp;quot;: '?'
      }));
    }

    $(this).find('.explain-trend').show();
  });

  // When moving off of this trend-item, hide the explain-trend link.
  $('.trend-item').live('mouseout', function(index) {
    $(this).find('.explain-trend').hide();
  });

  // When clicking an explain-link, find and display this Trend's explanation.
  $('.explain-trend').live('click', function() {
    TrendExplanation.open($(this).parent().find('.trend-link').text());

    return false;
  });

  // Build a footer with details about this script that can be attached to the dialog showing a Trend's explanation.
  var footer = $(&amp;quot;&amp;lt;p/&amp;gt;&amp;quot;).css({'border-top': '1px solid #eeeeee', 'font-size': 'smaller', 'margin-top': '10px', 'padding-top': '5px'})
    .append($('&amp;lt;span&amp;gt;Explanation from @&amp;lt;a href=&amp;quot;/#!/whatthetrend&amp;quot;&amp;gt;whatthetrend&amp;lt;/a&amp;gt;.&amp;lt;/span&amp;gt;'));
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;
</content>
    </entry>
  
    <entry>
      <title>Introducing My Rails Rumble 2010 Entry: do*connect</title>
      <link href="http://thomasmango.com/2010/10/17/introducing-my-rails-rumble-2010-entry-do-connect"/>
      <updated>2010-10-17T00:00:00+00:00</updated>
      <id>http://thomasmango.com/2010/10/17/introducing-my-rails-rumble-2010-entry-do-connect</id>
      <content type="html">&lt;p&gt;My entry to &lt;a href=&quot;http://railsrumble.com&quot;&gt;Rails Rumble 2010&lt;/a&gt; is a service called &lt;a href=&quot;http://thomasmango.com/projects/doconnect&quot;&gt;do*connect&lt;/a&gt;. If you don’t know what the Rails Rumble is, their site explains it as:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The Rails Rumble is a kickass 48 hour web application development competition. As a contestant, your team gets one caffeine-fueled weekend to design, develop, and deploy the best web property that you can, using the awesome power of Ruby and Rails.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;My application, do*connect, gives you a simple way to build and grow a third party developer community around your service. I decided on this project because I feel that developer communities are always hobbled together. Google Groups are often used as a mailing list, sometimes &lt;a href=&quot;http://tenderapp.com&quot;&gt;Tender Support&lt;/a&gt; is used for documentation (but usually just non-developer support), but many times services have to roll their own.&lt;/p&gt;

&lt;p&gt;Just look at &lt;a href=&quot;http://simplegeo.com/docs/&quot;&gt;SimpleGeo&lt;/a&gt;, &lt;a href=&quot;http://groups.google.com/group/foursquare-api&quot;&gt;Foursquare&lt;/a&gt; and &lt;a href=&quot;http://gowalla.com/api/docs&quot;&gt;Gowalla&lt;/a&gt;. Everyone does a great job hosting their documentation, but it shouldn’t be so time consuming to start a developer community around your web service. I hope that with do*connect, it won’t be.&lt;/p&gt;

&lt;p&gt;Regardless of the outcome of Rails Rumble 2010, I plan to continue expanding on do*connect. I have a handful of additional features I’d like to implement, including some premium ones. I haven’t decided on a cost yet for the premium service, but it will definitely support custom domains and a customizable appearance.&lt;/p&gt;

&lt;p&gt;The free version will continue to live on and I expect to add features like a status dashboard (another developer-facing resource that everyone builds themselves – see: &lt;a href=&quot;http://dev.twitter.com/status&quot;&gt;Twitter&lt;/a&gt;, &lt;a href=&quot;http://status.github.com/&quot;&gt;GitHub&lt;/a&gt;, &lt;a href=&quot;http://status.37signals.com/&quot;&gt;37signals&lt;/a&gt; and &lt;a href=&quot;http://status.simplegeo.com/&quot;&gt;SimpleGeo&lt;/a&gt;), announcements and extending discussions to act like a mailing list.&lt;/p&gt;

&lt;p&gt;One feature I’d like to highlight briefly, that isn’t shown in depth in the below screencast, is the permissions system. Communities can be open, closed or private. Open communities are publicly visible but require you to join to post. Closed communities aren’t publicly visible, but anyone can join. Private communities aren’t publicly visible and memberships must be approved by Community Managers. Additionally, Community Managers can promote any other member to be a Manager, giving them the ability to create Pages and Documentation as well as delete Pages, Documentation and Discussions. I’ve always been a fan of simple permissions and I think what do*connect supports is a nice balance between flexible and simple.&lt;/p&gt;

&lt;p&gt;Here’s a quick screencast to explain do*connect:&lt;/p&gt;

&lt;iframe src=&quot;http://www.screenr.com/embed/e7D&quot; width=&quot;650&quot; height=&quot;396&quot; frameborder=&quot;0&quot;&gt; &lt;/iframe&gt;
</content>
    </entry>
  
    <entry>
      <title>Testing for Booleans</title>
      <link href="http://thomasmango.com/2010/07/27/testing-for-booleans"/>
      <updated>2010-07-27T00:00:00+00:00</updated>
      <id>http://thomasmango.com/2010/07/27/testing-for-booleans</id>
      <content type="html">&lt;p&gt;I just released a new plugin called &lt;a href=&quot;http://github.com/tsmango/to_b&quot;&gt;to_b&lt;/a&gt;. Just like my other public projects on &lt;a href=&quot;http://github.com/tsmango&quot;&gt;github&lt;/a&gt;, this plugin is extremely simple and is meant to help with something I’ve found very annoying: the lack of a to_b method.&lt;/p&gt;

&lt;p&gt;Installing it in your Rails project will add a to_b method to NilClass, TrueClass, FalseClass, Fixnum and String. I’ve found this most useful when providing optional boolean parameters in API methods. I explain this situation a bit more in the README, which I’ll embed below.&lt;/p&gt;

&lt;h3 id=&quot;readme&quot;&gt;README&lt;/h3&gt;

&lt;p&gt;A simple plugin that adds a .to_b method to various classes to aide in testing
for boolean values against variously typed objects.&lt;/p&gt;

&lt;h3 id=&quot;why-nil-false-and-true&quot;&gt;Why nil, false and true&lt;/h3&gt;

&lt;p&gt;If you look at the source, you’ll note that nil.to_b returns nil, rather than
false. Additionally, a string like ‘notaboolean’.to_b also returns nil. This
was done on purpose. I always ensure all the boolean columns in my database
are created with :null =&amp;gt; false to avoid any issues relating to null values
in boolean fields. However, to_b returning nil in certain circumstances allows
me the flexibility when using this in conjunction with an API to accept nil,
false and true values for specific parameters.&lt;/p&gt;

&lt;p&gt;An example of why I want the ability to test for nil, false and true is that
if a boolean parameter is left out I want my SQL to search WHERE true OR false,
if the parameter is set to true I want it to search WHERE true and if the parameter
is false, false. It is simply easier to have a scope like the following:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/1163935.js?file=example-scope.rb&quot;&gt; &lt;/script&gt;

&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;named_scope :with_tip, lambda {|value| value.to_b.nil? ? {} : {:conditions =&amp;gt; {:tip =&amp;gt; value.to_b}}}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;

&lt;p&gt;Rather than explicitly searching WHERE true OR false, I simply leave out the
condition. When the value is true or false, I include the condition.&lt;/p&gt;

&lt;h3 id=&quot;examples&quot;&gt;Examples&lt;/h3&gt;

&lt;script src=&quot;https://gist.github.com/1163968.js?file=to_b-examples.rb&quot;&gt; &lt;/script&gt;

&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt; true.to_b
=&amp;gt; true

&amp;gt;&amp;gt; false.to_b
=&amp;gt; false

&amp;gt;&amp;gt; nil.to_b
=&amp;gt; nil

&amp;gt;&amp;gt; 'true'.to_b
=&amp;gt; true

&amp;gt;&amp;gt; 'TRUE '.to_b
=&amp;gt; true

&amp;gt;&amp;gt; 'false'.to_b
=&amp;gt; false

&amp;gt;&amp;gt; 'F'.to_b
=&amp;gt; false

&amp;gt;&amp;gt; 'random'.to_b
=&amp;gt; nil

&amp;gt;&amp;gt; 1.to_b
=&amp;gt; true

&amp;gt;&amp;gt; 0.to_b
=&amp;gt; false

&amp;gt;&amp;gt; 5.to_b
=&amp;gt; nil&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;
</content>
    </entry>
  
    <entry>
      <title>Geico's Payment Form: Indentation Matters</title>
      <link href="http://thomasmango.com/2010/07/20/geicos-payment-form-indentation-matters"/>
      <updated>2010-07-20T00:00:00+00:00</updated>
      <id>http://thomasmango.com/2010/07/20/geicos-payment-form-indentation-matters</id>
      <content type="html">&lt;p&gt;While paying my car insurance on Geico’s website this morning, I was faced with the same payment form that bothers me every month. Actually, it’s only one section of the form: the saved account section:&lt;/p&gt;

&lt;p class=&quot;image&quot;&gt;
  &lt;img src=&quot;http://thomasmango.com/images/2010/07/geicos-form.png&quot; /&gt;
&lt;/p&gt;

&lt;p&gt;Every time I come to this form, I instinctively check the box above my saved bank account information. However, if you read the label attached the checkbox you’ll see that the checkbox actually lets you use a &lt;em&gt;different&lt;/em&gt; account.&lt;/p&gt;

&lt;p&gt;The fact that the checkbox is above your saved account details and your saved account details are indented, leads you to believe that the checkbox is tied to that account.&lt;/p&gt;

&lt;p&gt;I mentioned this on Twitter and, within an hour, &lt;a href=&quot;http://twitter.com/geico_service&quot;&gt;@geico_service&lt;/a&gt; replied and said they’d tell the website team. I have no idea if they’ll fix it or not, but I figured that was my chance. I edited the html of the form quickly and sent them a mockup of what I always expect to see in that area:&lt;/p&gt;

&lt;p class=&quot;image&quot;&gt;
  &lt;img src=&quot;http://thomasmango.com/images/2010/07/suggested-geicos-form.png&quot; /&gt;
&lt;/p&gt;

&lt;p&gt;It’s a really minor change, but I think it helps a lot. The original form had the intention of allowing you to continue without doing anything. Your account information is saved so if you want to use it, don’t click anything. I think my mockup here drives that point home more.&lt;/p&gt;

&lt;p&gt;You have two options, the default is to use your saved account (notice the radio button is above the indented account details) and the second option, that isn’t selected by default, is below the saved account details and allows you to use a different account.&lt;/p&gt;

&lt;p&gt;Little things like this can go a long way when designing a form in your web application.&lt;/p&gt;
</content>
    </entry>
  
    <entry>
      <title>Thoughts on Draft</title>
      <link href="http://thomasmango.com/2010/06/26/thoughts-on-draft"/>
      <updated>2010-06-26T00:00:00+00:00</updated>
      <id>http://thomasmango.com/2010/06/26/thoughts-on-draft</id>
      <content type="html">&lt;p&gt;Earlier this week, &lt;a href=&quot;http://37signals.com&quot;&gt;37signals&lt;/a&gt; released their first &lt;a href=&quot;http://37signals.com/draft&quot;&gt;iPad application&lt;/a&gt;. Their app, called Draft, is billed as a “straightforward sketch app for iPad” and is being sold for $10.&lt;/p&gt;

&lt;p&gt;Reading on, I can see that:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“It only comes in black. You can draw in white or red.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“It automatically saves whatever you draw.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;At this point, I was baffled. I’m roughly three full screens down and three screenshots deep and it looks a lot like Adobe Ideas (which is free) and a host of other apps that are already available.&lt;/p&gt;

&lt;p&gt;But further down the page, there was more:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“You can share sketches via email or &lt;a href=&quot;http://campfirenow.com&quot;&gt;Campfire&lt;/a&gt;.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And there we go. There had to be a reason they were charging $10 for this app, we just had to find it.&lt;/p&gt;

&lt;p&gt;Now, the problem I have is with the way they’re marketing it. It’s a “sketch app” but oh it also let’s you “share via Campfire”. And judging from the &lt;a href=&quot;http://37signals.com/svn/posts/2420-launch-draft-for-ipad&quot;&gt;hundreds of comments&lt;/a&gt; on their announcement post, there were a lot of people calling them crazy for charging so much for an app that “doesn’t do anything more than Adobe Ideas”. Yet, it does do more and honestly, what are the chances that the minds behind &lt;a href=&quot;http://basecamphq.com&quot;&gt;Basecamp&lt;/a&gt;, &lt;a href=&quot;http://37signals.com/rework&quot;&gt;Rework&lt;/a&gt; and &lt;a href=&quot;http://37signals.com/svn&quot;&gt;SVN&lt;/a&gt;, aren’t damn sure of what they’re doing?&lt;/p&gt;

&lt;p&gt;But I’m getting ahead of myself. I should explain why I’m even writing about this. Over the past few years, I’ve started thinking more about building products than building applications. Not just “can this be done” or “what can be added”, but what makes this &lt;strong&gt;a product&lt;/strong&gt; and &lt;strong&gt;how do you sell it&lt;/strong&gt;. And by sell it, I mean “sell it” for either money or just getting people to buy into the idea. A lot of things have contributed to my thinking more about whole products over the years, and reading what 37signals has had to say is certainly one of those things.&lt;/p&gt;

&lt;h3 id=&quot;back-to-draft&quot;&gt;Back to Draft&lt;/h3&gt;

&lt;p&gt;Let’s first make something clear: the people behind 37signals are incredibly successful and know what they’re doing. They know how to give you what you need and they know how to make you want to take out your credit card. They do a lot of things well, and making money is seriously high on that list.&lt;/p&gt;

&lt;p&gt;With that aside, I think they could have launched (and can market) Draft in a much more effective way: by changing the name to “Draft for Campfire”. The only people who are going to buy this app are people who use Campfire. There just simply isn’t any reason to buy this over cheaper sketch apps, unless you use Campfire. And 37signals is clearly directing this at paying, Campfire users. If you had the choice, why would you even want people who won’t spend money on apps, when you have existing customers that probably pay you upwards of $150/year? Existing Campfire users: that’s who it’s useful to and that’s who, I can only assume, they want using it.&lt;/p&gt;

&lt;p&gt;So, Instead of taking the criticism, which 37signals &lt;a href=&quot;http://twitter.com/dhh/status/16879422570&quot;&gt;does a great job at&lt;/a&gt;, by changing the name to “Draft for Campfire”, I think that most people bashing them on that blog post would realize right away the point of the app. It’s no longer a sketch app that also can share via Campfire, it’s a sketch app &lt;strong&gt;for&lt;/strong&gt; sharing via Campfire.&lt;/p&gt;

&lt;p&gt;But it’s not just about negative feedback, it’s also about their marketing page. Their current marketing page does an awful job at immediately conveying to me the reason as to why I should buy this app for ten dollars. The fact that it &lt;strong&gt;can&lt;/strong&gt; share via Campfire (mentioned very low on the page), feels a lot different than if the product was billed as &lt;strong&gt;for&lt;/strong&gt; sharing via Campfire right off the bat - even though it’s the exact same app.&lt;/p&gt;

&lt;p&gt;It’s a small change, but I’d bet it makes a big difference to a lot of people landing on that page. Then again, I haven’t written &lt;a href=&quot;http://gettingreal.37signals.com&quot;&gt;two&lt;/a&gt; &lt;a href=&quot;http://37signals.com/rework&quot;&gt;books&lt;/a&gt; or launched a &lt;a href=&quot;http://37signals.com&quot;&gt;host of insanely successful applications&lt;/a&gt;, so what the hell do I know?&lt;/p&gt;
</content>
    </entry>
  
    <entry>
      <title>Transferring a Private Repository on Github</title>
      <link href="http://thomasmango.com/2010/06/24/transferring-a-private-repository-on-github"/>
      <updated>2010-06-24T00:00:00+00:00</updated>
      <id>http://thomasmango.com/2010/06/24/transferring-a-private-repository-on-github</id>
      <content type="html">&lt;h3 id=&quot;important-update-08-21-2011&quot;&gt;Important Update (08-21-2011)&lt;/h3&gt;

&lt;p&gt;GitHub now has a native support for transferring the ownership of a repository to another user. Just click into your repository’s admin area and scroll down to the Danger Zone™.&lt;/p&gt;

&lt;p class=&quot;image&quot;&gt;
  &lt;img src=&quot;http://thomasmango.com/images/2010/06/github-danger-zone.png&quot; /&gt;
&lt;/p&gt;

&lt;h3 id=&quot;original-post-06-24-2010&quot;&gt;Original Post (06-24-2010)&lt;/h3&gt;

&lt;p&gt;I recently had to transfer a private git repository that was being hosted on Github. It turned out to be embarrassingly easy to transfer the repository while keeping the history intact, but I figured I’d document it in case others were wondering.&lt;/p&gt;

&lt;h3 id=&quot;what-didnt-really-work&quot;&gt;What Didn’t Really Work&lt;/h3&gt;

&lt;p&gt;The first thing I tried was a fork. I added the receiver’s Github account as a collaborator to the private repository. Then, I forked the project on the receiver’s Github account. Afterwards, I &lt;em&gt;removed&lt;/em&gt; the receiver as a collaborator from the original project and &lt;em&gt;removed&lt;/em&gt; the original account as a collaborator on the newly forked project (which is automatically added by Github).&lt;/p&gt;

&lt;p&gt;More or less, this did the job. The newly forked project was it’s own repository and neither repository owner could see the other repository. The only issue was that the new repository still said “forked from {original account}”. The receiver wasn’t happy about this and to be honest, it was a little crude being that they purchased the codebase.&lt;/p&gt;

&lt;h3 id=&quot;the-correct-way&quot;&gt;The Correct Way&lt;/h3&gt;

&lt;p&gt;The correct way to do this is basically just as easy.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Create a new repository on Github under the receiver’s account.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Add someone with access to the original repository as a collaborator to the newly created repository owned by the receiver.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Duplicate your project directory locally (as someone who has access to both repositories).&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cp ./projects/{project_name} ./projects/{project_name}_backup&lt;/code&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Change into the project and remove the existing remote origin that points at the original repository.&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;
        &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cd projects/{project_name}&lt;/code&gt;&lt;/p&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git remote rm origin&lt;/code&gt;&lt;/p&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Add the new remote origin (see Github’s excellent &lt;a href=&quot;http://cl.ly/487aed0f71d395350ca4&quot;&gt;first run screen&lt;/a&gt;) that points to the newly created repository owned by the receiver.&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git remote add origin git@github.com:{receiver}/{repository_name}.git&lt;/code&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Push to the new repository.&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git push origin master&lt;/code&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Delete your local copy pointing to the new repository.&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;
        &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cd ..&lt;/code&gt;&lt;/p&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rm -rf ./projects/{project_name}&lt;/code&gt;&lt;/p&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mv ./projects/{prject_name}_backup ./projects/{project_name}&lt;/code&gt;&lt;/p&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This isn’t rocket science, but I figured it would help someone.&lt;/p&gt;
</content>
    </entry>
  
    <entry>
      <title>Resque in Production</title>
      <link href="http://thomasmango.com/2010/05/27/resque-in-production"/>
      <updated>2010-05-27T00:00:00+00:00</updated>
      <id>http://thomasmango.com/2010/05/27/resque-in-production</id>
      <content type="html">&lt;p&gt;Over at &lt;a href=&quot;http://limitedpressing.com&quot;&gt;Limited Pressing&lt;/a&gt;, we’re using a wonderful background queue called &lt;a href=&quot;http://github.com/defunkt/resque&quot;&gt;Resque&lt;/a&gt;. Resque was built by &lt;a href=&quot;http://twitter.com/defunkt&quot;&gt;Chris Wanstrath&lt;/a&gt; of Github fame and runs on top of &lt;a href=&quot;http://code.google.com/p/redis/&quot;&gt;Redis&lt;/a&gt;. It’s fantastic and I absolutely love it. If you haven’t had a chance to try it, go check it out.&lt;/p&gt;

&lt;p&gt;When setting up Resque in production, I ran into a few issues that weren’t extremely obvious to me. I ended up working through them in the end and thought I’d write something up to help others out in the future.&lt;/p&gt;

&lt;h3 id=&quot;monitoring-with-god&quot;&gt;Monitoring with God&lt;/h3&gt;

&lt;p&gt;Resque comes &lt;a href=&quot;http://github.com/defunkt/resque/blob/master/examples/god/resque.god&quot;&gt;bundled with a config file&lt;/a&gt; for &lt;a href=&quot;http://god.rubyforge.org/&quot;&gt;god&lt;/a&gt;, but I had an issue with the way it would start up a worker. My example is only using a single worker, but you can combine my method with the bundled one. Here’s how I did it:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/415369.js?file=monitor-redis-resque.rb&quot;&gt; &lt;/script&gt;

&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;# Redis
%w{6379}.each do |port|
  God.watch do |w|
    w.name          = &amp;quot;redis&amp;quot;
    w.interval      = 30.seconds
    w.start         = &amp;quot;/etc/init.d/redis start&amp;quot;
    w.stop          = &amp;quot;/etc/init.d/redis stop&amp;quot;
    w.restart       = &amp;quot;/etc/init.d/redis restart&amp;quot;
    w.start_grace   = 10.seconds
    w.restart_grace = 10.seconds

    w.start_if do |start|
      start.condition(:process_running) do |c|
          c.interval = 5.seconds
          c.running = false
      end
    end
  end
end

# Resque
God.watch do |w|
  w.name          = &amp;quot;resque-1.8.0&amp;quot;
  w.interval      = 30.seconds
  w.start         = &amp;quot;cd /var/www/apps/limitedpressing/current &amp;amp;&amp;amp; rake environment RAILS_ENV=production resque:work QUEUE=high,medium,low&amp;quot;
  w.start_grace   = 10.seconds

  # retart if memory gets too high
  w.transition(:up, :restart) do |on|
    on.condition(:memory_usage) do |c|
      c.above = 350.megabytes
      c.times = 2
    end
  end

  # determine the state on startup
  w.transition(:init, { true =&amp;gt; :up, false =&amp;gt; :start }) do |on|
    on.condition(:process_running) do |c|
      c.running = true
    end
  end

  # determine when process has finished starting
  w.transition([:start, :restart], :up) do |on|
    on.condition(:process_running) do |c|
      c.running = true
      c.interval = 5.seconds
    end

    # failsafe
    on.condition(:tries) do |c|
      c.times = 5
      c.transition = :start
      c.interval = 5.seconds
    end
  end

  # start if process is not running
  w.transition(:up, :start) do |on|
    on.condition(:process_running) do |c|
      c.running = false
    end
  end
end&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;

&lt;h3 id=&quot;restarting-workers-on-deploy&quot;&gt;Restarting Workers on Deploy&lt;/h3&gt;

&lt;p&gt;The other issue I ran into was that I needed my workers to restart each time I deployed. Because Resque loads your application’s environment, a new deploy with changed models, would mean that your existing Resque workers are running outdated code. The way I handled this was to QUIT my workers and let god start them back up (using the updated codebase).&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/415372.js?file=deploy.rb&quot;&gt; &lt;/script&gt;

&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;...

# Restart Passenger
deploy.task :restart, :roles =&amp;gt; :app do
  ...

  # Restart the resque workers
  run &amp;quot;cd #{current_path} &amp;amp;&amp;amp; rake queue:restart_workers RAILS_ENV=production&amp;quot;
end&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;

&lt;script src=&quot;https://gist.github.com/415372.js?file=resque.rake&quot;&gt; &lt;/script&gt;

&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;namespace :queue do
  task :restart_workers =&amp;gt; :environment do
    pids = Array.new

    Resque.workers.each do |worker|
      pids &amp;lt;&amp;lt; worker.to_s.split(/:/).second
    end

    if pids.size &amp;gt; 0
      system(&amp;quot;kill -QUIT #{pids.join(' ')}&amp;quot;)
    end

    system(&amp;quot;rm /var/run/god/resque-1.8.0*.pid&amp;quot;)
  end
end&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;

&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;At first, I wasn’t really happy about quitting and restarting my workers this way, but after reviewing how Resque handled &lt;a href=&quot;http://github.com/defunkt/resque/blob/master/lib/resque/worker.rb&quot;&gt;shutting down workers&lt;/a&gt;, it seemed like an okay approach. If you have any tips on how the environment can be reloaded without waiting for god to start new workers up, I’d like to hear them, so shoot me an email.&lt;/p&gt;

&lt;h3 id=&quot;update-02032011&quot;&gt;Update 02/03/2011&lt;/h3&gt;

&lt;p&gt;A special thanks to Nate Daiger of &lt;a href=&quot;http://chunkhost.com&quot;&gt;ChunkHost&lt;/a&gt; for pointing out a much better way of collecting the worker pids in my &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;queue:restart_workers&lt;/code&gt; rake task. Essentially, I was iterating over &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Resque.workers&lt;/code&gt; and calling &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#worker_ids&lt;/code&gt; on each worker. Nate pointed out that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#worker_ids&lt;/code&gt; actually returned all pids anyway so it was unnecessary to loop. Another thing he suggested was replacing the use of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#worker_pids&lt;/code&gt; with splitting the output of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#to_s&lt;/code&gt;. The idea here is that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#worker_pids&lt;/code&gt; uses &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ps&lt;/code&gt; under the hood and could erroneously pick up similarly named processes, such as resque_web.&lt;/p&gt;

&lt;p&gt;These improvements have already been applied to the above gists. Thanks, Nate!&lt;/p&gt;
</content>
    </entry>
  
    <entry>
      <title>Small Victories</title>
      <link href="http://thomasmango.com/2010/05/07/small-victories"/>
      <updated>2010-05-07T00:00:00+00:00</updated>
      <id>http://thomasmango.com/2010/05/07/small-victories</id>
      <content type="html">&lt;p&gt;I often find myself at the start of very large projects that are scheduled to ship in way less time than is seemingly necessary to complete them. However, I don’t think this is such a bad thing.&lt;/p&gt;

&lt;p&gt;The fastest way to get something out the door is to set an arbitrary ship date. I could iterate over the same algorithm or interface for weeks, perfecting it, if I had the time. But, if I did that, I’d never actually ship anything. And when it comes down to it, if you don’t ship software, you may as well not write software.&lt;/p&gt;

&lt;p&gt;At the start of a big project, I lay out the major things that need to be done. I write them all down in a list on a big whiteboard next to my desk. I set a date that isn’t very far away, a date I’d love to get this stuff out the door by, not necessarily a date that would give me enough time to feel comfortable. That’s the key, you shouldn’t have so much time that you feel comfortable that everything will be perfect. I’m not sure where I read it, but someone once wrote, if you aren’t embarrassed even a little when you ship something, you didn’t ship it soon enough.&lt;/p&gt;

&lt;p&gt;Once I get started on the project, I cross things off the list on my whiteboard, I don’t erase them. I make sure that the list is somewhat general at first. I try my best not to stay on one area of the project for too long. If I notice I’m spending too much time on one thing, it usually means I’m obsessing over some small detail. I step back, figure out what I need to do to round out the area and make it good enough to ship. Then, I take all of the small details that the perfectionist inside me would really like to finish, and I add those to a second list on my whiteboard.&lt;/p&gt;

&lt;p&gt;I keep iterating like this, moving from large area to large area and then circling back and crossing off smaller details where time permits. The best part of this is that as you move from large area to large area and cross things off, you start to get on a roll. Looking up at a huge whiteboard with tons of things crossed off gives you the feeling of accomplishment. I’d rather cross off ten small to-do items in a day than one large to-do item in two days. And let me be clear, it isn’t starting with a large to-do list. Large to-do lists never get done. You start with a small to-do list and as you cross off things because they’re good enough, you add much smaller to-do items to another list. Don’t keep adding things unless you’re also crossing things off.&lt;/p&gt;

&lt;p&gt;But, it isn’t just the &lt;em&gt;feeling&lt;/em&gt; of accomplishment. Because you’re worrying about the details later, the entire project progresses forward faster. If you need to ship something large in two weeks, you can still ship it if the majority of things across the board are done without worrying about completing every little tiny thing in each section before moving on to the next section.&lt;/p&gt;

&lt;p&gt;I usually end up being able to complete almost everything in my arbitrary timeframe, but by doing things this way, it lets me easily evaluate the necessity of specific items. I believe that constantly adjusting scope to what’s important now rather than blindly implementing some predetermined “feature list” is the only way to ship software on time. Who knows, by the time you ship, you may circle back to some little fringe feature that you realize isn’t even necessary anymore.&lt;/p&gt;

&lt;p&gt;Set a date and ship the damn thing.&lt;/p&gt;
</content>
    </entry>
  
    <entry>
      <title>Six Weeks Later</title>
      <link href="http://thomasmango.com/2010/02/01/six-weeks-later"/>
      <updated>2010-02-01T00:00:00+00:00</updated>
      <id>http://thomasmango.com/2010/02/01/six-weeks-later</id>
      <content type="html">&lt;p&gt;I spent the past six weeks working full time on &lt;a href=&quot;http://limitedpressing.com&quot;&gt;Limited Pressing&lt;/a&gt; and I’m really happy with what was accomplished. We teamed up with some big names to host charity auctions (as of this writing we’ve raised almost $15,000 that will be donated to Doctors Without Borders) and rolled out a lot of new features. The biggest feature we launched was our brand new &lt;a href=&quot;http://limitedpressing.com/stores&quot;&gt;Stores&lt;/a&gt; infrastructure that I think makes it incredibly easy (not to mention inexpensive) to get a site and store up and running for your label or band.&lt;/p&gt;

&lt;p&gt;Aside from software work, I was also able to get my feet wet over at Amazon with things like EC2 and RDS. Although there were a lot of new things I wanted to spend time learning that got overlooked, I hope to rectify that in the coming weeks.&lt;/p&gt;

&lt;p&gt;Starting today, I begin a brand new project with &lt;a href=&quot;http://en.wikipedia.org/wiki/Gary_Culliss&quot;&gt;Gary Culliss&lt;/a&gt; that I’m really looking forward to working on.&lt;/p&gt;
</content>
    </entry>
  
    <entry>
      <title>Why I Spent $60 On An Alarm Clock</title>
      <link href="http://thomasmango.com/2010/01/06/why-i-spent-60-on-an-alarm-clock"/>
      <updated>2010-01-06T00:00:00+00:00</updated>
      <id>http://thomasmango.com/2010/01/06/why-i-spent-60-on-an-alarm-clock</id>
      <content type="html">&lt;p&gt;For years, I used one of the original &lt;a href=&quot;http://ihomeaudio.com&quot;&gt;iHome&lt;/a&gt; iPod dock alarm clocks. I only docked my iPhone a few times - when I felt like listening to an audiobook without my earphones. Otherwise, I used it as an alarm clock. At least, I attempted to use it as an alarm clock.&lt;/p&gt;

&lt;p&gt;To set the time or set the alarm, you have to spin a wheel. A slow, loud, clicking wheel. Shortly after getting the clock, the wheel started to break. You would spin it one way and the time would start going in the opposite direction. But that wheel wasn’t even the worst part about it - nor the interference with my GSM phone. No, the worst part about it was that it wouldn’t keep time. It would lose a few minutes every month or so. I never knew what time it was and started looking at my phone to double check. I tried resetting it frequently, but gave up. Instead, I began to set my alarm for earlier and earlier to compensate.&lt;/p&gt;

&lt;p&gt;I should have replaced it years ago.&lt;/p&gt;

&lt;h3 id=&quot;what-do-clocks-even-cost&quot;&gt;What Do Clocks Even Cost?&lt;/h3&gt;

&lt;p&gt;Before I was given the iHome “clock” as a gift, I had a regular alarm clock. I don’t remember how or when it came into my possession. I would say a decade, at least, had gone by since I had actually purchased an alarm clock.&lt;/p&gt;

&lt;p&gt;Not knowing what alarm clocks cost, I &lt;a href=&quot;http://www.amazon.com/s/ref=nb_ss?url=search-alias%3Daps&amp;amp;field-keywords=alarm+clock&amp;amp;x=0&amp;amp;y=0&quot;&gt;searched Amazon&lt;/a&gt;. &lt;strong&gt;Wow&lt;/strong&gt;. There are clocks with big numbers, small numbers, weather reports and ceiling projectors. There are clocks that roll off your nightstand and hide. There are clocks with iPod docks. There are fold up clocks. There are wind up clocks. There are clocks with puzzles on top that, when the alarm goes off, forces you to find the pieces that were thrown into the air and put them back together on the top of the clock before the alarm shuts off. There are $5 clocks and there are $105 clocks.&lt;/p&gt;

&lt;h3 id=&quot;learning-my-lesson&quot;&gt;Learning My Lesson&lt;/h3&gt;

&lt;p&gt;Page after page, I began to see the problem. Every clock has a gimmick. Every clock does &lt;em&gt;something else&lt;/em&gt;. But I had that clock. I had the &lt;em&gt;do something else&lt;/em&gt; clock and it was horrible. It was so bad, it couldn’t even keep time.&lt;/p&gt;

&lt;p&gt;I tried to find the alarm clocks that were only alarm clocks. Weather reports? I don’t want you. Ceiling projector? Sorry, not for me. The clocks that were left ranged from $5 to $15. Each one had reviews that said something along the lines of “cheap, works well”.&lt;/p&gt;

&lt;p&gt;Unfortunately, these all &lt;em&gt;looked&lt;/em&gt; cheap. I started to think, what if &lt;strong&gt;these&lt;/strong&gt; clocks can’t even keep time. How long would these cheap clocks last? Sure, they were just clocks which is what I wanted, but I don’t want to have to buy another clock next year.&lt;/p&gt;

&lt;p&gt;Then I stumbled on the &lt;a href=&quot;http://www.amazon.com/American-Innovative-Neverlate-Executive-Alarm/dp/B0010DX8MI/ref=sr_1_10?ie=UTF8&amp;amp;s=electronics&amp;amp;qid=1262789831&amp;amp;sr=8-10&quot;&gt;Neverlate Executive Alarm Clock&lt;/a&gt;. I am not an executive. Nor do I need 21 separate alarm “banks”. But, something seemed right about this ridiculously expensive alarm clock. It was expensive, but it didn’t do anything &lt;em&gt;else&lt;/em&gt;. Sure, it has separate alarms for each day of the week in addition to seven daily alarms and a quick nap alarm. It also has a gradual wake setting (increasing alarm volume) and a decremental snooze interval (10 minutes first snooze, 5 minutes second snooze, etc).&lt;/p&gt;

&lt;p&gt;It has a lot of features, but each feature is alarm clock related. If there is an alarm clock out there that is actually a good alarm clock, I thought, this must be it. Did I spend too much money on an alarm clock? Yeah, probably. But I will say that I was able to set the clock up in just a couple of minutes and I woke up on time this morning to a nice alarm sound with a gradually increasing volume.&lt;/p&gt;

&lt;p&gt;It doesn’t matter if you’re writing a piece of software or making an alarm clock. Keep your product focused and you won’t end up with a wheel you need to spin 500 times to get from 12:00AM to 7:00AM or a clock that can’t even keep time.&lt;/p&gt;
</content>
    </entry>
  
    <entry>
      <title>One of Those End of The Year Posts</title>
      <link href="http://thomasmango.com/2009/12/31/one-of-those-end-of-the-year-posts"/>
      <updated>2009-12-31T00:00:00+00:00</updated>
      <id>http://thomasmango.com/2009/12/31/one-of-those-end-of-the-year-posts</id>
      <content type="html">&lt;p&gt;I suppose waiting until 11PM on December 31st is as good a time as any for an end of the year wrap up post, right?&lt;/p&gt;

&lt;h3 id=&quot;2009&quot;&gt;2009&lt;/h3&gt;

&lt;p&gt;The year really started early February for me with my Grandfather passing away. I’ve had relatives pass away before, but this was different. This was someone I was really close to and saw all the time. His death was sudden and was really hard to get past - not only for myself, but for the rest of my family. I don’t think I’m over it yet and I’m not sure I ever will be.&lt;/p&gt;

&lt;p&gt;The rest of the year, I buried myself in work. I would say that my Grandfather’s death was the reason, but to be honest, I’ve been burying myself in work since as far back as I can remember, so maybe this was just an excuse.&lt;/p&gt;

&lt;p&gt;Regardless, 2009 was a year of working hard - maybe too hard.&lt;/p&gt;

&lt;p&gt;The year started wrapping up on December 18th with my last day of new development on &lt;a href=&quot;http://gawkk.com&quot;&gt;gawkk&lt;/a&gt;. It’s been a long road. I was first hired by &lt;a href=&quot;http://en.wikipedia.org/wiki/Gary_Culliss&quot;&gt;Gary&lt;/a&gt; to work on gawkk at the start of 2007. Working part time, I was able to lay the groundwork. By September of 2007, I had left a software engineering job I had been at for over six years to work full time on gawkk.&lt;/p&gt;

&lt;p&gt;In the past two years, gawkk has grown and changed a lot. Towards the end, we were constantly trimming features and simplifying processes and user interaction. As it stands, I feel that gawkk is a superb video aggregator and discovery engine. Behind the scenes, it scours thousands of video hosting sites and automatically imports and categorizes everything it finds (millions of videos). For our end users, it provides a very simple way to share and discuss videos with their friends. Gawkk suppresses the noise from people you don’t care about, allowing the videos enjoyed by only your friends to surface just for you.&lt;/p&gt;

&lt;p&gt;With that said, the time has come to let gawkk do its thing and focus attention elsewhere.&lt;/p&gt;

&lt;p&gt;Other than working on gawkk full time through 2009, I’ve worked on a handful of very small freelance projects - all from clients I first did work for many years ago. I’ve released a &lt;a href=&quot;http://github.com/tsmango&quot;&gt;few simple plugins&lt;/a&gt; and worked on a bunch of new side projects that have taken up most of my nights and weekends.&lt;/p&gt;

&lt;h3 id=&quot;twenty-ten&quot;&gt;Twenty Ten&lt;/h3&gt;

&lt;p&gt;I’ll be starting the new year with an entire month of not doing any paid work. Instead, I will spend most days and nights slaving away on a couple of my side projects and reading every technical book I can get my hands on. Another one of my goals for this month is to completely refactor my mornings in an attempt to get a better work-at-home routine down. Lastly, I hope to squeeze in a couple of snowboarding day trips here and there, because there is nothing more relaxing to me than sitting at the top of a snow covered mountain.&lt;/p&gt;

&lt;p&gt;I hope to have my new morning routine all straightened out when February comes, because I’m lucky enough to be starting a brand new project with Gary. We’re completely changing direction with this project and I’m really excited to get rolling. It’s going to be really fun to use some of the new things in the Rails ecosystem that I’ve had my eye on as well as just getting to start a new, fresh project (I’m looking at you, &lt;a href=&quot;http://github.com/rails/rails&quot;&gt;Rails 3&lt;/a&gt;!). In addition to new Rails specific things, we plan on using AWS for our entire infrastructure. Everything from EC2 and RDS to S3 and CloudFront. I honestly can’t wait to get my hands on that infrastructure. Everything Amazon has been doing with their Web Services continues to impress me. Just the other day they released &lt;a href=&quot;http://developer.amazonwebservices.com/connect/ann.jspa?annID=579&quot;&gt;object versioning&lt;/a&gt; for S3 - really neat stuff.&lt;/p&gt;

&lt;p&gt;Aside from my plan, I hope that the Rails community continues to thrive and that, for everyone’s sake, this economy picks up in 2010.&lt;/p&gt;

&lt;p&gt;Happy New Year!&lt;/p&gt;
</content>
    </entry>
  
    <entry>
      <title>A Look Back At Staples</title>
      <link href="http://thomasmango.com/2009/12/16/a-look-back-at-staples"/>
      <updated>2009-12-16T00:00:00+00:00</updated>
      <id>http://thomasmango.com/2009/12/16/a-look-back-at-staples</id>
      <content type="html">&lt;p&gt;In early 2007, I was contracted to implement a document management web application for Staples Digital Copy Services. Customers can register and upload documents for very large jobs to Staples’ regional copy centers. The app handles documents for about ten locations. The only non-rails part was a multi-file uploader I wrote as a Java applet. Staples wanted drag and drop file uploading that also supported dropping multiple files at once, which I was able to do with Java.&lt;/p&gt;

&lt;p&gt;Certain privileged Staples employees can log in and download documents, read descriptions and manage which jobs have been completed.&lt;/p&gt;

&lt;p&gt;I was contacted a few days ago for a quote to work on a new feature for the application and was happy to see the app has been running smoothly these past few years. They keep adding locations to the system and it’s quickly closing in on managing 100,000 documents.&lt;/p&gt;
</content>
    </entry>
  
    <entry>
      <title>Automatically Resizing a Textarea's Height</title>
      <link href="http://thomasmango.com/2009/09/18/automatically-resizing-a-textareas-height"/>
      <updated>2009-09-18T00:00:00+00:00</updated>
      <id>http://thomasmango.com/2009/09/18/automatically-resizing-a-textareas-height</id>
      <content type="html">&lt;p&gt;Here is a simple Javascript method that can be used to automatically resize the height of a textarea based on the amount of content inside.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://prototypejs.org&quot;&gt;Prototype&lt;/a&gt; is used in this example.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://blog.slicedsoftware.com/post/191242481/automatically-resizing-a-textareas-height&quot;&gt;Click through&lt;/a&gt; if you don’t see the code snippet below.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/189275.js?file=resize.html&quot;&gt; &lt;/script&gt;

&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;!-- Automatically resize a textarea's height (like Facebook) --&amp;gt;

&amp;lt;textarea id=&amp;quot;comment&amp;quot; rows=&amp;quot;1&amp;quot; cols=&amp;quot;50&amp;quot;&amp;gt;&amp;lt;/textarea&amp;gt;

&amp;lt;script type=&amp;quot;text/javascript&amp;quot; charset=&amp;quot;utf-8&amp;quot;&amp;gt;
  function autoResize(fieldId) {
    var length = $(fieldId).value.length;

    if(length &amp;gt; 0) {
      $(fieldId).rows = Math.floor(length / $(fieldId).cols) + 1;
    } else {
      $(fieldId).rows = 1
    }
  }

  $('comment').observe('keyup', function(){autoResize('comment');});
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;
</content>
    </entry>
  
    <entry>
      <title>A Cacheable Hash That Stays Synced</title>
      <link href="http://thomasmango.com/2009/09/07/a-cacheable-hash-that-stays-synced"/>
      <updated>2009-09-07T00:00:00+00:00</updated>
      <id>http://thomasmango.com/2009/09/07/a-cacheable-hash-that-stays-synced</id>
      <content type="html">&lt;p&gt;Rails.cache freezes values in hashes that are cached directly. &lt;a href=&quot;http://github.com/tsmango/cacheable_hash&quot;&gt;CacheableHash&lt;/a&gt; is a wrapper for Hash objects that prevents that from happening. Changes to the Hash being wrapped are automatically persisted back to the cache store so that everything stays in sync.&lt;/p&gt;

&lt;p&gt;You can clone (or fork) my new MIT licensed plugin over at &lt;a href=&quot;http://github.com/tsmango/cacheable_hash&quot;&gt;github&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;example&quot;&gt;Example&lt;/h3&gt;

&lt;p&gt;An instance of CacheableHash is used like any other hash. A cache key is the only thing required.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/1164097.js?file=example-irb.rb&quot;&gt; &lt;/script&gt;

&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt; fruit = CacheableHash.new('fruit_hash_key', :hash =&amp;gt; {:apple =&amp;gt; 'red', :banana =&amp;gt; 'yellow'}, :expires_in =&amp;gt; 1.week)
&amp;gt;&amp;gt; fruit[:banana]
=&amp;gt; &amp;quot;yellow&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;

&lt;p&gt;Changes are automatically persisted.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/1164100.js?file=example-irb.rb&quot;&gt; &lt;/script&gt;

&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt; fruit = Rails.cache.read('fruit_hash_key')
&amp;gt;&amp;gt; fruit[:apple]
=&amp;gt; &amp;quot;red&amp;quot;

&amp;gt;&amp;gt; fruit[:apple] = 'green'

&amp;gt;&amp;gt; Rails.cache.read('fruit_hash_key')[:apple]
=&amp;gt; &amp;quot;green&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;

&lt;h3 id=&quot;about-synchronicity&quot;&gt;About Synchronicity&lt;/h3&gt;

&lt;p&gt;Whenever a method is called on an instance of CacheableHash, that instance automatically writes itself back to the cache store. Often, this is unnecessary. If you call .keys, for example, there is no reason to write back to the cache store. Only when reading a value from the hash using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[]&lt;/code&gt;, is the copy in the cache store not specifically updated. But, rather than worrying about the specific methods that change the contents of the hash, it’s safer to just update the instance in the cache store whenever not specifically reading values.&lt;/p&gt;
</content>
    </entry>
  
    <entry>
      <title>Updated: Mobile Twitter Trends Application (2.1)</title>
      <link href="http://thomasmango.com/2009/09/06/updated-mobile-twitter-trends-application-2-1"/>
      <updated>2009-09-06T00:00:00+00:00</updated>
      <id>http://thomasmango.com/2009/09/06/updated-mobile-twitter-trends-application-2-1</id>
      <content type="html">&lt;p&gt;I wasn’t able to add all of the polish and features to my &lt;a href=&quot;http://trends.slicedsoftware.com&quot;&gt;Trends&lt;/a&gt; application that I really felt was necessary last night, so I’ve just rolled out a quick update. This is definitely the last update for a while on this app.&lt;/p&gt;

&lt;p class=&quot;image&quot;&gt;
  &lt;img src=&quot;http://thomasmango.com/images/2009/06/trends-2-1.jpg&quot; /&gt;
&lt;/p&gt;

&lt;h3 id=&quot;version-21&quot;&gt;Version 2.1&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;The front page now lists not only the &lt;em&gt;currently&lt;/em&gt; trending topics on Twitter, but it also shows topics that have trended in the past day and the past week.&lt;/li&gt;
  &lt;li&gt;Hashtag topics are now working (they were broken in v2).&lt;/li&gt;
  &lt;li&gt;The timestamp on the topic page now more accurately states when the topic was &lt;em&gt;first seen&lt;/em&gt; trending.&lt;/li&gt;
  &lt;li&gt;Added some protection against strange (and actually kind of frequent) errors thrown by the Twitter API when requesting the list of trends.&lt;/li&gt;
  &lt;li&gt;If What the Trend doesn’t know about a particular topic, rather than throwing an error, you’re now redirected back to the trends list and a dialog is displayed telling you what happened.&lt;/li&gt;
  &lt;li&gt;Fixed a visual bug in TankEngine related to the top 1px border of the toolbar (it used to be a dark line, it now matches the actual iPhone toolbar element).&lt;/li&gt;
  &lt;li&gt;Updated the default loading image used for the fullscreen Trends application (accessed through the home screen shortcut) so that the toolbar matches the updated toolbar.&lt;/li&gt;
&lt;/ul&gt;
</content>
    </entry>
  
    <entry>
      <title>Mobile Twitter Trends Application</title>
      <link href="http://thomasmango.com/2009/09/05/mobile-twitter-trends-application"/>
      <updated>2009-09-05T00:00:00+00:00</updated>
      <id>http://thomasmango.com/2009/09/05/mobile-twitter-trends-application</id>
      <content type="html">&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; &lt;a href=&quot;http://thomasmango.com/2009/09/06/updated-mobile-twitter-trends-application-2-1&quot;&gt;Version 2.1 has been released&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Just over a month ago, I released a &lt;a href=&quot;http://trends.slicedsoftware.com&quot;&gt;mobile web application&lt;/a&gt; that used the API from &lt;a href=&quot;http://www.whatthetrend.com&quot;&gt;whatthetrend.com&lt;/a&gt; to present a list of recently trending topics on Twitter, along with their explanations. This little application turned out to be pretty handy, but for a while I’ve wanted to change it a bit. Most importantly, I wanted to have the front page of the application be the list of &lt;em&gt;currently&lt;/em&gt; trending topics on Twitter.&lt;/p&gt;

&lt;p class=&quot;image&quot;&gt;
  &lt;img src=&quot;http://thomasmango.com/images/2009/06/trends-2-0.jpg&quot; /&gt;
&lt;/p&gt;

&lt;h3 id=&quot;trends-version-2&quot;&gt;Trends: Version 2&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;The interface has been re-implemented from the ground up (actually the entire application was rewritten from scratch) and is now styled like a normal list-based iPhone application.&lt;/li&gt;
  &lt;li&gt;When you first load the application, it shows you a list of the topics that are currently trending on Twitter.&lt;/li&gt;
  &lt;li&gt;Clicking on a topic will bring you to that topic’s page. The explanation as to why that topic is trending is pulled in from What the Trend? and displayed here.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I will be adding lists for the daily trending topics as well as the trending topics for the week - for now, only the current trending topics are available.&lt;/p&gt;

&lt;p&gt;Please visit &lt;a href=&quot;http://trends.slicedsoftware.com&quot;&gt;Trends&lt;/a&gt; on your iPhone and add it to your home screen for the best experience.&lt;/p&gt;

&lt;h3 id=&quot;sweat-the-details&quot;&gt;Sweat the Details&lt;/h3&gt;

&lt;p&gt;For this project, I used Noel Rappin’s &lt;a href=&quot;http://github.com/noelrappin/tank-engine&quot;&gt;TankEngine&lt;/a&gt; plugin for the iPhone’s user interface. I ended up having to hack it a bit so that it would run in fullscreen mode without breaking out into Safari when clicking links, but overall it was very enjoyable to use. You can run the Trends application in fullscreen mode by tapping the + button in MobileSafari and then tapping ‘Add to Home Screen’. When you launch Trends from the new icon on your home screen, it will launch in fullscreen mode.&lt;/p&gt;

&lt;h3 id=&quot;heroku&quot;&gt;heroku&lt;/h3&gt;

&lt;p&gt;In addition to wanting to update this application a bit, I’ve been really wanting a reason to try &lt;a href=&quot;http://heroku.com/&quot;&gt;heroku&lt;/a&gt; and I thought this was the perfect application to use as my test run. heroku is a service that allows you to deploy ruby applications quickly and easily. You know what? Saying it allows you to deploy ruby applications quickly and easily is an &lt;em&gt;understatement&lt;/em&gt; – heroku is, by far, the most wonderful service I have used in recent memory. I set out tonight to rewrite my mobile Trends application from scratch. Once I had a working version, I went to heroku not knowing anything of how it worked, signed up and in less than two minutes my application was deployed to heroku and running perfectly.&lt;/p&gt;

&lt;p&gt;If you have a simple application that you’re planning to host on your own server, I highly suggest taking a minute to deploy it over at heroku. It’s free for small applications and I guarantee you will immediately see what an incredible service it is. I honestly can’t say enough.&lt;/p&gt;

&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;I don’t sleep enough and heroku is awesome.&lt;/p&gt;
</content>
    </entry>
  
    <entry>
      <title>Rails Rumble Reflections</title>
      <link href="http://thomasmango.com/2009/08/24/rails-rumble-reflections"/>
      <updated>2009-08-24T00:00:00+00:00</updated>
      <id>http://thomasmango.com/2009/08/24/rails-rumble-reflections</id>
      <content type="html">&lt;p&gt;I competed in &lt;a href=&quot;http://r09.railsrumble.com/&quot;&gt;Rails Rumble&lt;/a&gt; 2009 over the weekend. It was my first time competing, so I wanted to share some of what I learned while working on a project from start to finish with other people in a 48 hour window.&lt;/p&gt;

&lt;h3 id=&quot;get-a-real-designer&quot;&gt;Get a real designer&lt;/h3&gt;

&lt;p&gt;Our team consisted of three developers and no designers. We could all write HTML and CSS and develop front ends, but we weren’t designers. We didn’t possess the talent necessary to develop a really stunning interface, while actually developing the rest of the application in the time allotted.&lt;/p&gt;

&lt;p&gt;Although we produced a full featured application that ended up looking halfway decent, there is no doubt in my mind that we would have benefited immensely if we had a real designer. And by designer, I mean someone who actually makes a living doing design work for web applications.&lt;/p&gt;

&lt;h3 id=&quot;be-opinionated-but-be-flexible&quot;&gt;Be opinionated, but be flexible&lt;/h3&gt;

&lt;p&gt;Any project with multiple engineers is bound to bring about disagreements. People are going to discuss and argue their points. I believe that when it comes to software development, you must be opinionated to develop good software. Having strong opinions about something means you are passionate about it. When you’re constrained by a 48 hour window, being opinionated is even more important. You don’t have the luxury of having an entire discussion about every little thing that comes up.&lt;/p&gt;

&lt;p&gt;The problem is that when opinionated people disagree, they spend a lot of time in heated discussion. Normally, these discussions will lead to a better overall implementation and everyone benefits, but when you’re constrained by time, you must not only be opinionated, you must also be flexible. You have to pick your battles and make concessions.&lt;/p&gt;

&lt;h3 id=&quot;working-with-people-you-trust&quot;&gt;Working with people you trust&lt;/h3&gt;

&lt;p&gt;Being able to make concessions is related to another point I have. You should work with people you trust. If you don’t trust the people you are working with, you are going to have a hard time giving in when the other person yells louder. You aren’t going to be able to sit back and say:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“I’m working with this person for a reason. I have to trust them, they are very passionate about this.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Being able to trust your team members is not only important during a competition like this one, it’s always important. The difference with a competition, though, is that you just don’t have the time to spend on every disagreement.&lt;/p&gt;

&lt;h3 id=&quot;dont-write-tests&quot;&gt;Don’t write tests&lt;/h3&gt;

&lt;p&gt;Nowadays a lot of people talk about test drive development. Write tests for code that doesn’t exist yet. When you write the code, you know you’re done because it passes the tests. The problem with &lt;a href=&quot;http://en.wikipedia.org/wiki/Test-driven_development&quot;&gt;TDD&lt;/a&gt; is that it can be time consuming. Additionally, because you only have a 48 hour window, the scope of your application must be small enough to complete. If it’s small enough to complete, it will probably be small enough to manually test throughout the competition.&lt;/p&gt;

&lt;p&gt;I spoke to some other contestants who feel the same way. Some even went into the project doing tests and quickly abandoned them because they were too time consuming. Even &lt;a href=&quot;http://lowdownapp.com&quot;&gt;Lowdown&lt;/a&gt;, a Rails Rumble entry specifically built to help developers, designers and managers collaborate on &lt;a href=&quot;http://cukes.info/&quot;&gt;Cucumber&lt;/a&gt; feature stories &lt;a href=&quot;http://seancribbs.com/tech/2009/08/24/lowdown-our-rails-rumble-09-application/&quot;&gt;said&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Ironically – especially considering the purpose of our application - we didn’t test, spec, or write features. There were times we could have benefitted from TDD, but many other times it would have just slowed us down. We considered the app to be a prototype/proof-of-concept anyway, not a polished and hardened work of craftsmanship.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I think this is the key. Testing is good, but testing during the competition could prove fatal. If you only finish a third of your application because you were busy writing tests, you don’t get more points - even if that third is really perfect. It’s better to get to a feature complete state as early as possible and then iterate and iterate and iterate until the last moments of the competition.&lt;/p&gt;

&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;As you can probably tell, I am &lt;em&gt;very&lt;/em&gt; opinionated when it comes to software development. Being opinionated can also leak into the rest of my life. This article, these reflections, are &lt;em&gt;my&lt;/em&gt; reflections. I’m sure many other participants, possibly even my own teammates, don’t agree with me - I’m okay with that. The fact is, nothing I said here (other than having a real designer on your team) is necessarily “right”. It is, however, right for me and probably a lot of other people.&lt;/p&gt;

&lt;p&gt;In the end, I was lucky enough to work with smart people and smart people can work through differences to deliver something they are proud of. And despite our differences, the three of us were really happy that we were able to deliver the application we set out to develop. Being proud of that accomplishment is something we could all agree on.&lt;/p&gt;

&lt;p&gt;I’m really looking forward to Rails Rumble 2010.&lt;/p&gt;
</content>
    </entry>
  
    <entry>
      <title>Making Your Existing User Base Play Nice With Your Facebook Users</title>
      <link href="http://thomasmango.com/2009/08/20/making-your-existing-user-base-play-nice-with-your"/>
      <updated>2009-08-20T00:00:00+00:00</updated>
      <id>http://thomasmango.com/2009/08/20/making-your-existing-user-base-play-nice-with-your</id>
      <content type="html">&lt;p&gt;&lt;em&gt;This is the second article in a series dedicated to getting your existing rails application on Facebook without clawing your eyes out. You should read the &lt;a href=&quot;http://thomasmango.com/2009/08/19/getting-your-existing-rails-app-on-facebook&quot;&gt;first article&lt;/a&gt; if you haven’t already.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In the previous article, I talked about how to use facebooker to extend your existing rails application with Facebook only views. Requests that came into your application &lt;em&gt;from&lt;/em&gt; Facebook, were authenticated by facebooker to be genuine Facebook requests, the Facebook user was required to add your application and all of your Facebook specific &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.fbml.erb&lt;/code&gt; views and layouts were automatically used instead of your standard &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.html.erb&lt;/code&gt; views. While all of this was happening for requests coming from Facebook, your regular application kept chugging along, doing its own thing, unaware you were cheating on it with that blue haired girl from your Calc class.&lt;/p&gt;

&lt;p&gt;Chances are however, your application has users (at least you hope it does). What you really want, is for users on your existing Rails app and new users coming in through Facebook to be treated like equal citizens. Sure you may email one and you may notify another, but aside from how you communicate with them, the content they generate in your application should be shared by everyone. If data generated by regular users and Facebook users couldn’t be seen or accessed by one another, there would be no reason to having a single action with two different views (html, fbml).&lt;/p&gt;

&lt;p&gt;There are a few things we need to get our different types of users to play nicely.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;A place to store a user’s Facebook user id and last session key.&amp;lt;/li&amp;gt;&lt;/li&gt;
  &lt;li&gt;A way to catch authenticated Facebook sessions for new users to our application.&amp;lt;/li&amp;gt;&lt;/li&gt;
  &lt;li&gt;A way to automatically log in an existing user who has authenticated via a Facebook request.&amp;lt;/li&amp;gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;tracking-facebook-account-details-in-your-users-table&quot;&gt;Tracking Facebook Account Details in Your Users Table&lt;/h3&gt;

&lt;p&gt;If you only plan on doing Facebook related stuff (you have no interest in having Twitter oauth support in your app in the future), the easiest thing to do is just add a couple of fields to your User model. We can just pull these migration lines from what facebooker does:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/1165228.js?file=&quot;&gt; &lt;/script&gt;

&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;add_column :users, :facebook_id, :integer, :limit =&amp;gt; 20, :null =&amp;gt; false
add_column :users, :session_key, string&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;

&lt;h3 id=&quot;tracking-facebook-account-details-in-a-separate-object&quot;&gt;Tracking Facebook Account Details in a Separate Object&lt;/h3&gt;

&lt;p&gt;Alternatively, if you plan on having not only Facebook authentication, but Twitter oauth at some point, you may want to create a new model called FacebookAccount to store your user’s Facebook account details (as well as a foreign key back to the User it belongs to). Then you can add a TwitterAccount object as well and do what you have to do.&lt;/p&gt;

&lt;p&gt;For this example, I’ll assume you just added some fields to your User.&lt;/p&gt;

&lt;h3 id=&quot;hey-do-i-know-you&quot;&gt;Hey, do I know you?&lt;/h3&gt;

&lt;p&gt;Now that we have a place to store Facebook account details, we need a way to make a new User for a new Facebook user. Let me preface this by saying that there are probably a hundred different ways to do this. What I’m going to detail, however, is the approach that worked well for me.&lt;/p&gt;

&lt;p&gt;Let’s go back to our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;application_controller&lt;/code&gt; and see how we left it:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/1165232.js?file=&quot;&gt; &lt;/script&gt;

&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;before_filter :require_login_for_facebook

def require_login_for_facebook
  if params[:format] == 'fbml'
    ensure_authenticated_to_facebook

    if !session[:facebook_session].nil?
      # we'll do something with users
      # here in the next post about fb
    end
  end
end&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;

&lt;p&gt;If you follow a Facebook request coming into our application, you’ll see that it hits the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;require_login_for_facebook&lt;/code&gt; before filter, it should pass the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(params[:format] == 'fbml')&lt;/code&gt; test because facebooker will have forced the format to be fbml because it already verified the request came from Facebook. Next, the famous &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ensure_authenticated_to_facebook&lt;/code&gt; method is called to make sure we get a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Facebooker::Session&lt;/code&gt;. After that, I do one more test to ensure we really do have a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Facebooker::Session&lt;/code&gt; sitting in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;session[:facebook_session]&lt;/code&gt; and we can be on our way.&lt;/p&gt;

&lt;p&gt;Inside of the if statement checking if &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;!session[:facebook_session].nil?&lt;/code&gt;, we’re going to want something along the lines of:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/1165233.js?file=&quot;&gt; &lt;/script&gt;

&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;unless user_logged_in? or (controller_name == 'facebook' and action_name == 'connect')
  facebook_session = session[:facebook_session]

  if user = User.find(:first, :conditions =&amp;gt; {:facebook_id =&amp;gt; facebook_session.user.uid})
    session[:user_id] = user.id
  else
    redirect_to :controller =&amp;gt; 'facebook', :action =&amp;gt; 'connect'
  end
end&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;

&lt;p&gt;I should probably mention that I don’t use &lt;a href=&quot;http://github.com/technoweenie/restful-authentication/tree/master&quot;&gt;restful-authentication&lt;/a&gt;. I generally roll my own. Please, take a minute to yell and scream about what a horrible person I am. Blah blah blah. Okay, done? Despite not using the norm, you can see some of the same basic things here. First up, I have a helper method called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;user_logged_in?&lt;/code&gt;. Can you guess what that does? Good. I’m sure you have the same kind of method. Just make sure there isn’t already someone logged in. Don’t worry about that next part of the unless statement ensuring we aren’t in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FacebookController#connect&lt;/code&gt;, you’ll understand that soon.&lt;/p&gt;

&lt;p&gt;So, after we ensure we have a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Facebooker::Session&lt;/code&gt;, we make sure there isn’t someone already logged in. Next, we try and locate the User in our users table that has a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;facebook_id&lt;/code&gt; that matches the user id of the Facebook authenticated user (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;session[:facebook_session].user.uid&lt;/code&gt;). If we find someone with that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;facebook_id&lt;/code&gt;, we can automatically log them in. For me, I set &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;session[:user_id]&lt;/code&gt;, for everyone else in the world, do what you normally do to log someone in.&lt;/p&gt;

&lt;p&gt;The reason we can automatically log this person in is because that user already had to log into Facebook and when Facebook made a request to us, facebooker did the heavy lifting to ensure that this was &lt;em&gt;a real Facebook&lt;/em&gt; request. We wouldn’t have gotten this far if it wasn’t a real Facebook request. And, since this &lt;strong&gt;is&lt;/strong&gt; a real Facebook request, we can assume the uid of the user inside of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Facebooker::Session&lt;/code&gt; is really who they say they are. Thus, they are sufficiently authenticated.&lt;/p&gt;

&lt;p&gt;But how do we actually get a user object with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;facebook_id&lt;/code&gt; into the database so that we actually have someone to automatically log in? It’s actually pretty easy. First, generate a controller called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FacebookController&lt;/code&gt;. Inside of this controller, create a method called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;connect&lt;/code&gt;. I know, I know, Facebook Connect! Although I won’t be talking about it in this article, this is actually in preparation for allowing users to add your Facebook app inside of Facebook, then go out to your existing external application and log in using Facebook Connect while still retaining the same user object they used from your Facebook applicaiton.&lt;/p&gt;

&lt;p&gt;Inside of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FacebookController#connect&lt;/code&gt; method, you’re going to want to prepare a new User model. This method is going to act like a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Users#new&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Users#create&lt;/code&gt; method. The idea is that we need this user to essentially register for our site. User’s in our existing rails app register, so why not Facebook users? The difference, however, is that we want to ask for as little information as possible while still being able to have full fledged accounts for Facebook users that can be shown on our existing site. For me, that means I need a username. Just pick a username and I’ll be happy. Oh, and don’t forget to add an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;app/views/facebook/connect.fbml.erb&lt;/code&gt; view for this method (for Facebook Connect, we’d have a connect.html.erb - get it?).&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/1165239.js?file=&quot;&gt; &lt;/script&gt;

&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;def connect
  if request.get?
    # Lets collect some information about this user
    @facebook = Hash.new
    @facebook[:id] = facebook_session.user.uid
    @facebook[:name] = facebook_session.user.name
    @facebook[:description] = facebook_session.user.about_me
    @facebook[:image_small] = facebook_session.user.pic_square_with_logo
    @facebook[:image_large] = facebook_session.user.pic_big
    @facebook[:profile_url] = facebook_session.user.profile_url.gsub(/^http:\/\/www\.facebook\.com\//, '')

    # We're going to want this later, no point in hitting the API again
    session[:facebook_credentials] = @facebook

    # To make things easier, I like to suggest a username.
    # I won't do it here, but generally I run the suggested username
    # through a unique_username? check about 3 times, appending a
    # random integer on the end to try and make it unique.
    # If I can't find a unique username quickly, I let the user worry about it.

    @user = User.new
    if !@facebook[:profile_url].blank? and !@facebook[:profile_url][/^profile.php/]
      # This user has a new vanity url so that is a preferred username
      @user.username = @facebook[:profile_url].first(15).gsub(/\s/, '').gsub(/\./, '')
    elsif !@facebook[:name].blank?
      # This user doesn't have a vanity url, just use their name
      @user.username = @facebook[:name].first(15).gsub(/\s/, '').gsub(/\./, '')
    end
  else
    @facebook = session[:facebook_credentials]

    # Create the new User object from params[:user]
    # Make sure to store the @facebook[:id] and session key (see facebooker docs)
    # Fetch and store their avatar locally (Facebook likes you to use their (x)fbml
    # tags to display a user's current profile picture, you could do that instead.)

    # Log the user in
    session[:user_id] = @user.id

    redirect_to path_to_front_page
  end
end&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;

&lt;p&gt;I know it looks like there’s a lot going on in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;connect&lt;/code&gt; method, but it’s pretty straight forward and the inline documentation should really explain everything. Obviously, you’ll want a form in your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;app/views/facebook/connect.fbml.erb&lt;/code&gt; view. You’ll need a username field and you’ll probably want to display the image in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@facebook[:image_small]&lt;/code&gt; on the page somewhere.&lt;/p&gt;

&lt;p&gt;Now, whenever an existing Facebook user comes back to your application, they will automatically be logged in with their full fledged account. They never have to worry about logging in or the fact that they “registered”. In fact, I tell my user’s they are just picking a username. That &lt;em&gt;is&lt;/em&gt; technically all they’re doing. Having to “register” scares people off. Picking a username is easy.&lt;/p&gt;

&lt;p&gt;I may write another article that explains how you can setup Facebook Connect to allow your existing Facebook users to log in directly at your main external rails app (outside of Facebook), using Facebok Connect. Doing this would actually allow you to get users to sign up using Facebook Connect directly from your main site as well. After the post connect callback from Facebook Connect, you’d just the same kind of the check in the application controller to see if you have the user with that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;facebook_id&lt;/code&gt;, either log them in automatically or send them off to your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FacebookController#connect&lt;/code&gt; method (only it will be the .html.erb version this time) to finish the account sign up. It’s really very similar to what we do here.&lt;/p&gt;
</content>
    </entry>
  
    <entry>
      <title>Getting Your Existing Rails App on Facebook</title>
      <link href="http://thomasmango.com/2009/08/19/getting-your-existing-rails-app-on-facebook"/>
      <updated>2009-08-19T00:00:00+00:00</updated>
      <id>http://thomasmango.com/2009/08/19/getting-your-existing-rails-app-on-facebook</id>
      <content type="html">&lt;p&gt;There’s a ton of information already out there about writing a new Facebook app with Ruby on Rails. You use &lt;a href=&quot;http://github.com/mmangino/facebooker&quot;&gt;facebooker&lt;/a&gt;, you call a method at the top of your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;application_controller&lt;/code&gt; and you’re done. It’s pretty easy. The problem is that when you have an existing Rails app and you want to extend it to support alternate fbml views for a Facebook application, things are a bit trickier.&lt;/p&gt;

&lt;p&gt;Here’s how I did it:&lt;/p&gt;

&lt;p&gt;You’ll have to start with the usual setup:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Create a Facebook app from the &lt;a href=&quot;http://www.facebook.com/developers&quot;&gt;Developer Application&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Install the &lt;a href=&quot;http://github.com/mmangino/facebooker&quot;&gt;plugin&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Setup your ssh tunnel for development&lt;/li&gt;
  &lt;li&gt;Setup your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config/facebook.yml&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I won’t bother explaining how to do all of this stuff. There are &lt;a href=&quot;http://www.pragprog.com/titles/mmfacer/developing-facebook-platform-applications-with-rails&quot;&gt;tons&lt;/a&gt; of &lt;a href=&quot;http://www.pragprog.com/screencasts/v-mmfacer/rails-development-for-the-facebook-platform&quot;&gt;resources&lt;/a&gt; out &lt;a href=&quot;http://peepcode.com/products/rails-on-facebook&quot;&gt;there&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After you get that done, it’s time to start serving authenticated fbml views for requests coming from Facebook. In the facebooker world, you need to call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ensure_authenticated_to_facebook&lt;/code&gt;. Unfortunately, if you do that in your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;application_controller&lt;/code&gt;, it will try and do a Facebook authentication for every request coming into your application, not just the ones actually coming from Facebook. Since you are trying to extend your existing application with Facebook views, this isn’t what you want.&lt;/p&gt;

&lt;p&gt;It turns out that facebooker does two very important things for you by just having the plugin configured in your application. The first is that it forces the format of all of the Facebook requests to be fbml. Next, it adds an object to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;session[:facebook_session]&lt;/code&gt;. It’s safe to say that if your request has a format of fbml and there is something in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;session[:facebook_session]&lt;/code&gt;, you’ve got yourself a Facebook request.&lt;/p&gt;

&lt;p&gt;To catch and authenticate just the requests coming from Facebook, you’ll want to add the next bit of code to your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;application_controller&lt;/code&gt;:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/1165276.js?file=&quot;&gt; &lt;/script&gt;

&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;before_filter :require_login_for_facebook

def require_login_for_facebook
  if params[:format] == 'fbml'
    ensure_authenticated_to_facebook

    if !session[:facebook_session].nil?
      # we'll do something with users
      # here in the next post about fb
    end
  end
end&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;

&lt;p&gt;Now, let’s say you have a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;movies_controller&lt;/code&gt; that uses an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;app/views/layouts/movies.html.erb&lt;/code&gt; layout. You’ll want to add an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;app/views/layouts/movies.fbml.erb&lt;/code&gt; layout for requests coming from Facebook. Next, you want a Facebook specific view for your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;index&lt;/code&gt; action. You already have an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;app/views/movies/index.html.erb&lt;/code&gt; right? Well, just add an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;app/views/movies/index.fbml.erb&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That’s it, you’re done! Now, when a request comes into your regular application for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/movies&lt;/code&gt;, the regular &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;index.html.erb&lt;/code&gt; view will be rendered inside of your regular &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;movies.html.erb&lt;/code&gt; template. But, when a request comes in from your Facebook application to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/fb-app-name/movies&lt;/code&gt;, it’s authenticated with facebooker, the facebook user will have to have added your application and your new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;index.fbml.erb&lt;/code&gt; view will automatically be rendered inside of your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;movies.fbml.erb&lt;/code&gt; layout.&lt;/p&gt;

&lt;p&gt;I will post another article soon talking about how to approach integrating your existing user base with a Facebook user base.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Like this article? Be sure to read the &lt;a href=&quot;http://thomasmango.com/2009/08/20/making-your-existing-user-base-play-nice-with-your&quot;&gt;second article&lt;/a&gt; in this series titled: “Making Your Existing User Base Play Nice With Your Facebook User Base”.&lt;/em&gt;&lt;/p&gt;
</content>
    </entry>
  
    <entry>
      <title>Keeping Text Fields and Text Areas Consistent With CSS</title>
      <link href="http://thomasmango.com/2009/08/08/keeping-text-fields-and-text-areas-consistent-with-css"/>
      <updated>2009-08-08T00:00:00+00:00</updated>
      <id>http://thomasmango.com/2009/08/08/keeping-text-fields-and-text-areas-consistent-with-css</id>
      <content type="html">&lt;p&gt;Let me just start by saying that I don’t claim to be good at design at all, but as I don’t work with a designer, I have had to fend for myself over the years. I’d say I “get by” in the design department by sticking to things that aren’t overly complicated. It’s probably also worth noting that I can be a perfectionist at times. I care a lot about the code I produce - whether it’s 5 lines of code that can be written more simply or a few pixels lining up better (admittedly, I’m way better at refactoring code than I am at interfaces).&lt;/p&gt;

&lt;p&gt;What I’d like to explain is a very simple thing I do to keep my text fields and text areas looking consistent with just a couple lines of CSS.&lt;/p&gt;

&lt;p&gt;By default, most browsers like Safari and Firefox render text fields with a simple 3D type depth. It makes the field stand out. Text areas, on the other hand, are usually rendered without that 3D type effect. They are given a simple, flat border. This is what 2 text fields look like compared to a text area, by default, without any CSS:&lt;/p&gt;

&lt;p class=&quot;image&quot;&gt;
  &lt;img src=&quot;http://thomasmango.com/images/2009/08/text-fields-no-border.png&quot; /&gt;
&lt;/p&gt;

&lt;p&gt;The first step to keeping things consistent looking is to simply set the border of text fields and text areas with CSS. Now both widgets are at a level playing field.&lt;/p&gt;

&lt;p class=&quot;image&quot;&gt;
  &lt;img src=&quot;http://thomasmango.com/images/2009/08/text-fields-border.png&quot; /&gt;
&lt;/p&gt;

&lt;p&gt;Just setting the border is a nice first step, but that slight 3D depth given to text fields by default is actually pretty useful to indicate to the user that she can click and type into the area. To do this, you can simply set the border-top of the text fields and text areas to be slightly darker than the border you set in the last step.&lt;/p&gt;

&lt;p class=&quot;image&quot;&gt;
  &lt;img src=&quot;http://thomasmango.com/images/2009/08/text-fields-border-with-depth.png&quot; /&gt;
&lt;/p&gt;

&lt;p&gt;I suspect that most users looking at this form wouldn’t even think twice about this subtle tweak, and that’s the beauty of it. It’s so simple yet still does such a great job of making your forms look way, way sexier.&lt;/p&gt;

&lt;p&gt;Sample CSS:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/1165286.js?file=&quot;&gt; &lt;/script&gt;

&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;.textfield, textarea {
  border: 1px solid #c9c2c1;
  border-top: 1px solid #999999;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;

&lt;p&gt;Maybe the word for me is neurotic.&lt;/p&gt;
</content>
    </entry>
  
    <entry>
      <title>PGnJ 1.1 - Free For Good, QuickJoin, Crasher Fix</title>
      <link href="http://thomasmango.com/2009/08/07/pgnj-1-1-free-for-good-quickjoin-crasher-fix"/>
      <updated>2009-08-07T00:00:00+00:00</updated>
      <id>http://thomasmango.com/2009/08/07/pgnj-1-1-free-for-good-quickjoin-crasher-fix</id>
      <content type="html">&lt;p&gt;After 8 months of being on sale, I would like to announce that &lt;a href=&quot;http://thomasmango.com/projects/pgnj&quot;&gt;PGnJ 1.1&lt;/a&gt; is now available and that it is completely free (and that it will absolutely stay free).&lt;/p&gt;

&lt;p&gt;It comes down to the fact that the vast majority of PGnJ’s user base decided to stay on 0.8 (the last free version). There wasn’t huge interest in a pay version of PGnJ and because of that, interaction with customers along with feedback totally dropped off the map. But I still had things I wanted to add to PGnJ. I still use PGnJ every day. I wanted people to get those new features. So, the PGnJ-for-pay experiment is officially over.&lt;/p&gt;

&lt;p&gt;What’s new in 1.1? The &lt;a href=&quot;http://thomasmango.com/files/PGnJ/changes.txt&quot;&gt;changelog&lt;/a&gt; may look pretty slim but it comes with a couple of very major improvements as well as a fix for a crashing bug that came about in the past couple of weeks.&lt;/p&gt;

&lt;p&gt;Changelog:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;PGnJ is now &lt;strong&gt;free&lt;/strong&gt;. Enjoy!&lt;/li&gt;
  &lt;li&gt;When using the DataBrowser (double click a table from the database tree in the sidebar), you can how double click any cell to edit the contents (PostgreSQL and MySQL only).&lt;/li&gt;
  &lt;li&gt;Developed a brand new, one of a kind feature that I call QuickJoin. When you open the DataBrowser, it will automatically add a QuickJoin bar to the top of the window with a list of all foreign keys for the current table. Clicking a foreign key will bring up a drop down list of all fields in the referenced table. Selecting a column (you can select as many as you want, across as many referenced tables as you want) will automatically generate JOINs under the hood and display the selected column right inline next to the fk column. See below for a quick demonstration.&lt;/li&gt;
  &lt;li&gt;Fixed a major crashing bug that came about with OS X Java Update 4. Essentially, the application must be run in 32 bit mode.&lt;/li&gt;
&lt;/ul&gt;

&lt;iframe src=&quot;http://player.vimeo.com/video/28060086?byline=0&amp;amp;portrait=0&amp;amp;color=195baa&quot; width=&quot;600&quot; height=&quot;473&quot; frameborder=&quot;0&quot;&gt;&lt;/iframe&gt;
</content>
    </entry>
  
    <entry>
      <title>Using Partials as Reusable Inner Layouts</title>
      <link href="http://thomasmango.com/2009/08/05/using-partials-as-reusable-inner-layouts"/>
      <updated>2009-08-05T00:00:00+00:00</updated>
      <id>http://thomasmango.com/2009/08/05/using-partials-as-reusable-inner-layouts</id>
      <content type="html">&lt;p&gt;You may find this pretty basic, but it’s useful nonetheless.&lt;/p&gt;

&lt;p&gt;Using partials in Rails is a wonderful example of code reuse. For example, you may have comments that use polymorphism so that you can attach comments to different models in your system. If you always want your comments to display using the same UI (and why wouldn’t you) on not only Project Messages but also To Do items, you can create a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/comments/_comment&lt;/code&gt; partial and render these partials from either the Project Message page or the To Do item page. But, we all knew that.&lt;/p&gt;

&lt;p&gt;Sometimes, however, you may want to use a partial like an inner layout inside of your page’s layout.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/162703.js?file=&quot;&gt; &lt;/script&gt;

&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;!-- /dashboard/_container - This partial is used as a template --&amp;gt;

&amp;lt;table id=&amp;quot;dashboard&amp;quot;&amp;gt;
  &amp;lt;tr&amp;gt;
    &amp;lt;td id=&amp;quot;tabs&amp;quot;&amp;gt;
      &amp;lt;!-- Links to different areas of the dashboard --&amp;gt;
    &amp;lt;/td&amp;gt;
    &amp;lt;td id=&amp;quot;main&amp;quot;&amp;gt;
      &amp;lt;%= yield %&amp;gt;
    &amp;lt;/td&amp;gt;
  &amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;


&amp;lt;!-- /messages/_inbox - This partial uses the dashboard _container as a wrapper --&amp;gt;

&amp;lt;% render(:layout =&amp;gt; &amp;quot;/dashboard/container&amp;quot;, :locals =&amp;gt; {:selected =&amp;gt; 'inbox'}) do -%&amp;gt;
  &amp;lt;div id=&amp;quot;messages&amp;quot;&amp;gt;
    &amp;lt;%= render @messages %&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;% end -%&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;

&lt;p&gt;Above is a really simple example, demonstrating how you can use a partial as an “inner layout”. Essentially this allows you to have a reusable partial with contextual, custom view code somewhere inside that reusable template - just like you’d use a regular page layout, except now you can have them scattered about your application.&lt;/p&gt;

&lt;p&gt;Yes, this example in particular is really simple, but if you’ve never seen partials used this way, your brain is probably already cranking on how immensely useful this can be.&lt;/p&gt;
</content>
    </entry>
  
    <entry>
      <title>A better Array#rand</title>
      <link href="http://thomasmango.com/2009/07/02/a-better-array-rand"/>
      <updated>2009-07-02T00:00:00+00:00</updated>
      <id>http://thomasmango.com/2009/07/02/a-better-array-rand</id>
      <content type="html">&lt;p&gt;I &lt;a href=&quot;http://github.com/tsmango/rand&quot;&gt;released a new plugin today&lt;/a&gt;, called rand. This plugin expands on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#rand&lt;/code&gt; method ActiveSupport adds to Array.&lt;/p&gt;

&lt;p&gt;As background, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rand&lt;/code&gt; method that Rails gives you, returns a single random value back from the array it’s called on.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/1165329.js?file=&quot;&gt; &lt;/script&gt;

&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt; [0, 1, 2, 3, 4].rand
=&amp;gt; 2&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;

&lt;p&gt;This rand plugin overrides the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rand&lt;/code&gt; method so that you can pass in an integer value that corresponds to how many random values from the array you actually want back.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/1165327.js?file=&quot;&gt; &lt;/script&gt;

&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt; [0, 1, 2, 3, 4].rand(2)
=&amp;gt; [4, 0]

&amp;gt;&amp;gt; [0, 1, 2, 3, 4].rand(4)
=&amp;gt; [3, 0, 2, 1]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;

&lt;p&gt;Additionally, the existing functionality is still in place so that if you don’t pass in a parameter, it still gives you back a single random value.&lt;/p&gt;
</content>
    </entry>
  
    <entry>
      <title>A better Rails.cache.increment</title>
      <link href="http://thomasmango.com/2009/06/25/a-better-rails-cache-increment"/>
      <updated>2009-06-25T00:00:00+00:00</updated>
      <id>http://thomasmango.com/2009/06/25/a-better-rails-cache-increment</id>
      <content type="html">&lt;p&gt;I started working with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Rails.cache.increment&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Rails.cache.decrement&lt;/code&gt; today but quickly found that it didn’t work as I planned. For example, it seemed that when calling these methods they would return the previous value rather than the newly incremented value. Additionally, if you decided to read directly using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Rails.cache.read&lt;/code&gt; and the same key, it would always return nil despite being able to call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Rails.cache.increment&lt;/code&gt; again. Another annoying thing is that if you tried to increment a value that wasn’t in memcached, instead of defaulting to 1, it returned nil. Just all sorts of wacky stuff going on. I decided to just write my own.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/135972.js?file=&quot;&gt; &lt;/script&gt;

&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;# app/models/util/cache.rb

class Util::Cache
  def self.increment(key, amount = 1)
    if (value = Rails.cache.read(key)).nil?
      Rails.cache.write(key, (value = amount))
    else
      Rails.cache.write(key, (value = value + amount))
    end

    return value
  end

  def self.decrement(key, amount = 1)
    if (value = Rails.cache.read(key)).nil?
      value = 0
    else
      Rails.cache.write(key, (value = value - amount))
    end

    return value
  end
end&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;
</content>
    </entry>
  
    <entry>
      <title>Generating RSS Feeds in Rails</title>
      <link href="http://thomasmango.com/2009/04/01/generating-rss-feeds-in-rails"/>
      <updated>2009-04-01T00:00:00+00:00</updated>
      <id>http://thomasmango.com/2009/04/01/generating-rss-feeds-in-rails</id>
      <content type="html">&lt;p&gt;It’s very easy to generate RSS feeds in Rails. In fact, if there is any possible benefit to having RSS feeds in your rails application, there is absolutely no reason you shouldn’t take a few minutes and set them up.&lt;/p&gt;

&lt;p&gt;These days, you just have to create a file like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:action.rss.builder&lt;/code&gt; to go along with your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:action.html.erb&lt;/code&gt; file. You don’t even need a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;respond_to&lt;/code&gt; block in your action. As long as you have a route setup that knows how to handle additional formats, rails will automatically render your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.rss.builder&lt;/code&gt; file rather than your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.html.erb&lt;/code&gt; file if an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.rss&lt;/code&gt; extension is at the end of the url.&lt;/p&gt;

&lt;p&gt;For the basics of generating RSS feeds in rails, check out this &lt;a href=&quot;http://railscasts.com/episodes/87-generating-rss-feeds&quot;&gt;screencast&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you’d like to include media in your RSS feeds you should use the Yahoo media namespace xml definitions. To include this namespace in your feed you can use:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/1165347.js?file=&quot;&gt; &lt;/script&gt;

&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;xml.rss(:version =&amp;gt; &amp;quot;2.0&amp;quot;, &amp;quot;xmlns:media&amp;quot; =&amp;gt; 'http://search.yahoo.com/mrss/')&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;

&lt;p&gt;You can then generate a namespaced XML element like this:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/1165348.js?file=&quot;&gt; &lt;/script&gt;

&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;xml.media(:content, :url =&amp;gt; &amp;quot;some-image-url&amp;quot;, :type =&amp;gt; &amp;quot;image/jpeg&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;
</content>
    </entry>
  
    <entry>
      <title>I Searched and Searched for searchd</title>
      <link href="http://thomasmango.com/2009/03/16/i-searched-and-searched-for-searchd"/>
      <updated>2009-03-16T00:00:00+00:00</updated>
      <id>http://thomasmango.com/2009/03/16/i-searched-and-searched-for-searchd</id>
      <content type="html">&lt;p&gt;For a while now I’ve been working on a really long and detailed post comparing the different search systems available for rails projects. I just deleted the draft.&lt;/p&gt;

&lt;p&gt;I deleted it because I realized there really isn’t anything to compare. If you don’t &lt;strong&gt;need&lt;/strong&gt; live updated search results and you can live with an index that’s updated every 15 minutes or more, just use Sphinx. Sphinx with &lt;a href=&quot;http://ts.freelancing-gods.com&quot;&gt;Thinking Sphinx&lt;/a&gt; by &lt;a href=&quot;http://twitter.com/pat&quot;&gt;Pat Allan&lt;/a&gt; is simply the most elegant, full featured and most importantly, &lt;strong&gt;stable&lt;/strong&gt; search system available for rails today. We’ve been using it over at &lt;a href=&quot;http://gawkk.com&quot;&gt;gawkk&lt;/a&gt; for months now and haven’t had a single unhappy moment since we switched from Solr.&lt;/p&gt;

&lt;p&gt;SQL searches are slow. Ferret is crap in production. Solr is almost as unstable as Ferret in production and will bring down your database with unnecessary connections every time a damn object is instantiated. Sphinx is rock solid and fast as hell.&lt;/p&gt;

&lt;p&gt;I will only offer two lines of proof:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/1165358.js?file=&quot;&gt; &lt;/script&gt;

&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;total 1133325 docs, 266596694 bytes
total 117.702 sec, 2265011.00 bytes/sec, 9628.75 docs/sec&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;

&lt;p&gt;Over a million documents in 117 seconds. Try and do that with anything other than Sphinx. I dare you.&lt;/p&gt;
</content>
    </entry>
  
    <entry>
      <title>A Simple .union Extension For ActiveRecord</title>
      <link href="http://thomasmango.com/2009/02/27/a-simple-union-extension-for-activerecord"/>
      <updated>2009-02-27T00:00:00+00:00</updated>
      <id>http://thomasmango.com/2009/02/27/a-simple-union-extension-for-activerecord</id>
      <content type="html">&lt;p&gt;I just wrote and &lt;a href=&quot;http://github.com/tsmango/union&quot;&gt;released my first rails plugin&lt;/a&gt;, called union. It’s absurdly simple and fairly naive. I wrote this plugin so that I didn’t have to look at an ugly UNION I was running in a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;find_by_sql&lt;/code&gt;.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/1165362.js?file=&quot;&gt; &lt;/script&gt;

&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;ActiveRecord::Base.union(parts, options = {})&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;

&lt;p&gt;The first parameter, parts, is an array of hashes. Each hash is what you would normally send into a single find and represents each SELECT. All parts will be unioned together.&lt;/p&gt;

&lt;p&gt;The second parameter, options, is a hash of remaining options to be applied to the UNION of the parts (ie: order, limit, offset).&lt;/p&gt;

&lt;p&gt;A simple (and useless) example would be:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/1165363.js?file=&quot;&gt; &lt;/script&gt;

&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;User.union([{:conditions =&amp;gt; ['name = ?', 'tom']}, {:conditions =&amp;gt; ['name = ?', 'gary']}], {:order =&amp;gt; 'created_at'})&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;

&lt;p&gt;This example produces the following SQL:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/1165366.js?file=&quot;&gt; &lt;/script&gt;

&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;(SELECT * FROM `users` WHERE (name = 'tom')) UNION (SELECT * FROM `users` WHERE (name = 'gary')) ORDER BY created_at;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;

&lt;p&gt;Essentially you can do any union, but it’s up to you to make sure you don’t pass the wrong stuff in because it’s a pretty dumb implementation.&lt;/p&gt;
</content>
    </entry>
  
    <entry>
      <title>MySQL Isn't Very Sensitive</title>
      <link href="http://thomasmango.com/2009/02/11/mysql-isnt-very-sensitive"/>
      <updated>2009-02-11T00:00:00+00:00</updated>
      <id>http://thomasmango.com/2009/02/11/mysql-isnt-very-sensitive</id>
      <content type="html">&lt;p&gt;When writing SQL conditions in MySQL, using an equal sign is case insensitive. For example:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/1165375.js?file=&quot;&gt; &lt;/script&gt;

&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;SELECT * FROM comments WHERE thread_id = '2A';&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;

&lt;p&gt;Will return results where thread_id actually equals 2a and 2A. To make this case sensitive, you can use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LIKE BINARY&lt;/code&gt;:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/1165376.js?file=&quot;&gt; &lt;/script&gt;

&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;SELECT * FROM comments WHERE thread_id LIKE BINARY '2A';&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;

&lt;p&gt;But what happens when you want to use IN? For example:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/1165377.js?file=&quot;&gt; &lt;/script&gt;

&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;SELECT * FROM comments WHERE thread_id IN ('2A', '2B', '2C');&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;

&lt;p&gt;This would return where thread_id actually equals 2a, 2A, 2b, 2B, 2c and 2C. This is no good because I need it to be case sensitive. You could do something like:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/1165379.js?file=&quot;&gt; &lt;/script&gt;

&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;SELECT * FROM comments
WHERE thread_id LIKE BINARY '2A'
OR thread_id LIKE BINARY '2B'
OR thread_id LIKE BINARY '2C';&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;

&lt;p&gt;But this is a problem when you want dynamically built this query using an ActiveRecord find method like:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/1165380.js?file=&quot;&gt; &lt;/script&gt;

&lt;noscript&gt;
&lt;div class=&quot;code-snippet&quot;&gt;
&lt;pre&gt;&lt;code&gt;Comment.find(:all, :conditions =&amp;gt; ['thread_id IN (?)', ['2A', '2B', '2C']])&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/noscript&gt;

&lt;p&gt;I haven’t found a solution yet, but I hope to soon.&lt;/p&gt;
</content>
    </entry>
  
    <entry>
      <title>A Fresh Start</title>
      <link href="http://thomasmango.com/2009/01/14/a-fresh-start"/>
      <updated>2009-01-14T00:00:00+00:00</updated>
      <id>http://thomasmango.com/2009/01/14/a-fresh-start</id>
      <content type="html">&lt;p&gt;I picked up a 320GB 7200RPM hard drive for my MacBook Pro and rather than cloning my current drive, I figured I’d take the opportunity to start fresh.&lt;/p&gt;

&lt;p&gt;Starting fresh is kind of scary when you’re a software engineer because you have to get your environment setup just the way you like it before you can really get started on work again. While I’m waiting for the last of my files to back up, I thought it’d be nice to detail how I prepare for a fresh operating system install.&lt;/p&gt;

&lt;p&gt;I have a Western Digital 1.5TB USB hard drive connected to my machine at all times running Time Machine backups. While I feel this keeps me safe for day to day operations, when I do a fresh install I always do a manual backup of the things I need. You can never have too many backups.&lt;/p&gt;

&lt;p&gt;First I copy over my main directories in my home directory. OS X makes this easy. I backup:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;~/Desktop&lt;/li&gt;
  &lt;li&gt;~/Documents&lt;/li&gt;
  &lt;li&gt;~/Downloads&lt;/li&gt;
  &lt;li&gt;~/Library&lt;/li&gt;
  &lt;li&gt;~/Movies&lt;/li&gt;
  &lt;li&gt;~/Music&lt;/li&gt;
  &lt;li&gt;~/Pictures&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I then export important data from applications to make it easy to import in my fresh install. I export from:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Address Book&lt;/li&gt;
  &lt;li&gt;Camino (Bookmarks)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next, I take various lists of things I have installed and screenshots of my current setup.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;I run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ls -la&lt;/code&gt; in my /Applications directory and copy the output to a text file&lt;/li&gt;
  &lt;li&gt;I run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gem list&lt;/code&gt; and copy that to a text file&lt;/li&gt;
  &lt;li&gt;I run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;which&lt;/code&gt; on various binaries like gem, ruby, rails to ensure my paths are setup properly when I reinstall&lt;/li&gt;
  &lt;li&gt;I take a screenshot of my Dock&lt;/li&gt;
  &lt;li&gt;I take a screenshot of my Menubar&lt;/li&gt;
  &lt;li&gt;I take a screenshot of System Preferences&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Stragglers:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;I copy my ~/.ssh directory so that I have my ssh keys&lt;/li&gt;
  &lt;li&gt;I copy various config files such as ~/.gitconfig&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I then copy my ~/Development directory which contains things like:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;~/Development/assets&lt;/li&gt;
  &lt;li&gt;~/Development/cocoa&lt;/li&gt;
  &lt;li&gt;~/Development/iphone&lt;/li&gt;
  &lt;li&gt;~/Development/java&lt;/li&gt;
  &lt;li&gt;~/Development/rails&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each of my ~/Development/ directories has directories like ./documentation/ and ./projects/.&lt;/p&gt;

&lt;p&gt;Lastly, I make backups of all of my development PostgreSQL and MySQL databases using pgAdmin and MySQL Administrator, respectively.&lt;/p&gt;
</content>
    </entry>
  
    <entry>
      <title>Working From Home</title>
      <link href="http://thomasmango.com/2008/12/12/working-from-home"/>
      <updated>2008-12-12T00:00:00+00:00</updated>
      <id>http://thomasmango.com/2008/12/12/working-from-home</id>
      <content type="html">&lt;p&gt;It’s incredible how much you can get done when working from home. Before I went full time at Gawkk over a year ago, I had a software engineering job at a regular company. I was in an office. People would call all day. People would stop by. I had to physically go to meetings. It really affected productivity.&lt;/p&gt;

&lt;p&gt;When I started working from home, I thought that it would be tough.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“I’ll really need to try and concentrate. There will just be so many distractions.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I mean, it’s what everyone was telling me.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“You’re going to work from home? Wow, I could never do that. I’d never get anything done!”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But really, what distractions are there? You don’t have to stop what you’re working on to make it to a meeting. You don’t have to answer the phone calls from people who don’t want to wait for a response from an email. You also don’t have people dropping by to just shoot the breeze.&lt;/p&gt;

&lt;p&gt;Once you realize that 9 to 5 isn’t when you have to be productive. Everything else falls into place. Sure, I like to generally be at my desk before 9 and I try and remember to pull myself away after 5 (although I can get sucked into my code), but if I was up late the night before and feel better starting at 10, it’s not that big of a deal. The key is working when you are productive. There is no sense at sitting at your desk doing nothing from 9 to 10 if on that particular morning you feel like crap. Work when you are productive and the distraction-less environment will help facilitate that.&lt;/p&gt;

&lt;p&gt;It probably also helps if you actually enjoy doing what you do.&lt;/p&gt;
</content>
    </entry>
  
    <entry>
      <title>Customer Support</title>
      <link href="http://thomasmango.com/2008/12/10/customer-support"/>
      <updated>2008-12-10T00:00:00+00:00</updated>
      <id>http://thomasmango.com/2008/12/10/customer-support</id>
      <content type="html">&lt;p&gt;A few days ago, I ordered a pair of snowboard pants from &lt;a href=&quot;http://www.the-house.com&quot;&gt;The House&lt;/a&gt;. When they showed up last night they were the wrong size. Further investigation revealed that the drop down containing sizes on their website listed them wrong. The size I selected was not the size they thought I ordered.&lt;/p&gt;

&lt;p&gt;Luckily, The House has great customer support. I called the toll free number and a woman answered immediately. No automated menus. She answered, I said I was sent the wrong size, she transferred me to the right person.&lt;/p&gt;

&lt;p&gt;The person who I was transferred to helped me find a different pair of pants. Discounted them. Ensured they would ship the same day and gave me free shipping on them. In the box will be the return shipping labels for the pants that were the wrong size so that I won’t have to pay shipping to send those back.&lt;/p&gt;

&lt;p&gt;There was only one painful part of the experience. The on hold music was just a single song on loop. &lt;a href=&quot;http://www.gawkk.com/james-brown-i-feel-good-http-leplubo-nn-cx-video-izle-indir-download/discuss&quot;&gt;James Brown’s “I Feel Good”&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
  
    <entry>
      <title>The Road to 1.0</title>
      <link href="http://thomasmango.com/2008/12/02/the-road-to-1-0"/>
      <updated>2008-12-02T00:00:00+00:00</updated>
      <id>http://thomasmango.com/2008/12/02/the-road-to-1-0</id>
      <content type="html">&lt;p&gt;Almost four years in the making, I’m very pleased to announce version 1.0 of my Database Development Environment, &lt;a href=&quot;http://thomasmango.com/projects/pgnj&quot;&gt;PGnJ&lt;/a&gt;. Although it started as a side project, since February’s release of 0.8, I have kicked developed into high gear. My goal was to release version 1.0 by year’s end. A goal that I am very happy to have met.&lt;/p&gt;

&lt;p&gt;When it came time to lock down what I felt would be worthy of the 1.0 badge, I found myself back at the roots of PGnJ’s design. Rather than simply packing PGnJ with the same old features that other database clients all have, I tried my best to stay true to the fact that PGnJ is meant to be a development aid. For example, I was less concerned with the standard table modification wizards that you see everywhere, than I was with a flexible system that could be extended in future releases. This is where SQL Templates were born. PGnJ 1.0 comes with a few stock DDL SQL Templates for easily creating and altering tables and columns. These templates include :variables that can be easily navigated using SHIFT+TAB and even special :type variables that show a tooltip with commonly used data types for the current database. In a future (already in the works) release of PGnJ, you will even be able to edit these templates as well as create your own.&lt;/p&gt;

&lt;p class=&quot;image&quot;&gt;
  &lt;img src=&quot;http://thomasmango.com/images/2008/12/sql-templates.png&quot; /&gt;
&lt;/p&gt;

&lt;p&gt;Although there is already a &lt;a href=&quot;http://thomasmango.com/files/PGnJ/changes.txt&quot;&gt;long list of new features and refinements&lt;/a&gt; in 1.0, for me it still comes down to PGnJ staying out of your way and at the same time making it as easy as possible for you to get your database work done.&lt;/p&gt;

&lt;p&gt;Thank you to everyone who has sent feedback and used PGnJ in the past. I hope that you continue to send any and all comments you may!&lt;/p&gt;
</content>
    </entry>
  
</feed>