Skip to content

Deploying a Rails Application to Amazon EC2 using Rubber: A Primer

2012 May 27
Comments Off on Deploying a Rails Application to Amazon EC2 using Rubber: A Primer
by Alec

If you’re inexperienced deploying Rails apps, or any apps for that matter, using EC2 for the first time can be rather daunting. All those acronyms! Elastic Block Store? Elastic IPs? WTF!? What happened to the hostnames, physical servers, and DNS configurations I know!?

So, naturally, you look for deployment help to get an instance running quickly. Rubber seems like a great candidate! Three commands, and it just works? Fantastic! Well, deployment is a rather difficult thing to automate, and providing a robust out of the box solution that fits everyone’s needs is rather difficult. In this case, the default
rubber vulcanize complete_passenger_postgresql
installs ALL KINDS of things that you probably don’t want for your tiny test app. There is even mention of the full stack being “pretty memory intensive” and requiring an m1.medium instance to be performant! Well gee, why do I need a MEDIUM instance costing $115/month ($0.16/hour X 24 X 30) for my staging app? That’s ridiculous!

Most people would probably give up on Rubber and just try installing the software manually — all those linux packages, apache, postgres, passenger, rails, dozens of gems. Sure, it’d be faster to get it up and running, and I would actually recommend this approach to beginners to learn the tech stack before turning to automation. Rubber is NOT A BEGINNER’S TOOL, and trying to use it without understanding what it does will be an exercise in extreme frustration (trust me).

So, a more sane baseline setup, for a simple deployment of a staging instance with rails/apache/passenger and your favorite database:

rubber vulcanize base
rubber vulcanize apache
rubber vulcanize passenger
rubber vulcanize postgresql
(or mysql of course)

This avoids all the extraneous monitoring software good for production servers, but not so good for your staging instances. However, of course, isolating the bare configurations doesn’t guarantee that they’ll work well together, so there are a number of additional changes to make to the generated .rb deployment instructions and .yml configurations:

  1. Leave the default scm deployment configuration as it is: trying to check out the source during initial deployment will likely fail, as the new instance will not yet have had a ssh keypair generated.
  2. Figure out the various roles for your particular deployment. For a vanilla apache/passenger/postgres environment, mine looked like this: web,apache,app,passenger,db,postgresql,postgresql_master
  3. Change rubber_passenger.yml to listen on the default web ports: 80, and 443 if you have SSL support.

Undoubtedly you will have other configuration tweaks to make, but that should cover the most important stuff. Ideally, someone should come up with a base_apache_passenger rubber template that includes the above tweaks. Good luck!

Rubber password hiccup

2012 May 23
Comments Off on Rubber password hiccup
by Alec

Since this same thing has tripped me up TWICE now, unbelievably, I thought I’d just put it out on the interwebs. I’ve been using rubber lately to deploy a rails app to Amazon EC2, and it’s mostly been painless. However, when running rubber:create_staging, at one point it prompts you for a sudo password to edit the /etc/hosts file. This is your LOCAL SYSTEM PASSWORD, not your EC2 instance’s root password (which probably doesn’t even exist). Rubber wants to use an alias to connect to the server, and chances are you haven’t set up the DNS to point to the just-created instance, so the workaround is to add the alias to your local machine’s recognized hosts. There you go.

SkiUtah iOS App

2012 February 11
Comments Off on SkiUtah iOS App
by Alec

After three plus months, I finally released my first iOS app. The project came more or less from out of the blue; when STS hit me up even though I had never touched Objective-C before. Apparently iOS developers are hard to find. The line “so you wanna get paid to learn iOS?” sounded pretty good, so I started studying the existing codebase (the app was already at version 2). They wanted a complete rebranding of the app as well as a number of new screens, so I ended up keeping maybe 5% of the existing codebase and rewriting the rest.

It was an excellent project for learning the iOS ecosystem: not too complicated, but with enough UI customizations to cover most of the UIKit framework; an existing codebase to build from; a relaxed deadline (eventually). Of course, the project scope ballooned to about 3x its original — I ended up adding a major “stats” feature with four additional screens, intro animation, an iPad version, and a stripped-down “embedded” version for strategic placement in kiosks around the state. This added a good two extra months of work, but the resulting Universal app is pretty sweet. Check it out on the App Store (Ski Utah Snow Report).

Thanks to STS and Ski Utah for putting an app together that we (the designers, developers, and Utah winter enthusiasts) can be proud of!

iOS Loading Screen Flash Animation

2011 December 30
Comments Off on iOS Loading Screen Flash Animation
by Alec

Edit: I can no longer recommend using a webview in this instance, as there’s no (easy) way to detect when the animation is done playing, at least when using a Swiffy-generated HTML page. Instead, in this instance I converted the flash animation to a .mp4 and used an MPMoviePlayerController rather than a WebView. The splash image implementation remains the same.

I’ve been working on a refresh of the Ski Utah iPhone app and had a specific requirement for an animated loading screen. But like the rest of the platform, Apple has a standardized protocol for application load screens. Provide a PNG, and that will be displayed while the application actually loads in the background.

Well, PNGs obviously can’t be animated, so we needed another approach. I was not tasked with coming up with the actual animation, and was provided a Flash file by Super Top Secret. Flash was the quickest way to come up with a few animation ideas, but couldn’t be run natively on the device, so we turned to Google’s Swiffy tool to output an HTML5 version. Only one of the brainstormed animations was simple enough to run smoothly in Safari, so the next step was to seamlessly transition from the loading screen to a WebView showing the HTML5 page.

After researching a few existing apps, I tried adding the WebView to the initial application frame, but there was always a delay between the loading PNG being hidden and the page being loaded. So, I added a separate PNG to display while the page loaded in the background. UIWebViewDelegate lets me know when the page has been loaded, so simply implementing webViewDidFinishLoad:(UIWebView *)webView did the trick. When the method is called, hide the transition image so the web view is visible. At that point, the animation plays in the browser. Then, a simple timer hides the web view and loads the app’s main screen after a hardcoded length of time.

So, it goes something like this:

  1. (app is launched by user)
  2. Default.png displays (as usual)
  3. iOS calls application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions on the AppDelegate. Here we create a SplashViewController which both initializes the web view and displays a transitional UIImageView, which is identical to Default.png.
  4. Once the HTML page is loaded, the callback is called. Remove the UIImageView to reveal the UIWebView beneath.
  5. On iOS < 5, there seemed to be a slight delay between when the callback is called and the animation begins. So, we put in [self performSelector:@selector(showWebView) withObject:nil afterDelay:0.5] to delay hiding the image view. Then, another timer is set to hide the web view after three seconds.

The animation ends up being seamless on both iOS4 and 5. Success!

Here’s the code:

SplashViewController.m fragment:

- (void)loadView
{
    appDelegate = (SkiUtahAppDelegate *) [[UIApplication sharedApplication] delegate];
 
    CGRect appFrame = [[UIScreen mainScreen] applicationFrame];
    UIView *view = [[UIView alloc] initWithFrame:appFrame];
    view.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;
    self.view = view;
    [view release];
 
    webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, -20, 490, 704)];
    webView.scalesPageToFit = YES;
    webView.delegate = self;
    NSString *htmlPath = [[NSBundle mainBundle] pathForResource:@"startup" ofType:@"html"];
    NSURLRequest *urlRequest = [NSURLRequest requestWithURL:[NSURL fileURLWithPath:htmlPath]];
    [webView loadRequest:urlRequest];
    [self.view addSubview:webView];
 
    splashImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"Default"]];
    splashImageView.frame = CGRectMake(0, -20, 320, 480);
    [self.view addSubview:splashImageView];
}
 
- (void)webViewDidFinishLoad:(UIWebView *)webView {
    if([Utils systemVersionLessThan:@"5.0"]) {
        [self performSelector:@selector(showWebView) withObject:nil afterDelay:0.5];
    } else {
        [self performSelector:@selector(showWebView) withObject:nil afterDelay:0.0];
    }
}
 
- (void)showWebView {
    [splashImageView removeFromSuperview];
 
    if([Utils systemVersionLessThan:@"5.0"]) {
        [self performSelector:@selector(continueWithApp) withObject:nil afterDelay:4.5];
    } else {
        [self performSelector:@selector(continueWithApp) withObject:nil afterDelay:3.0];
    }
}
 
- (void)continueWithApp {
    appDelegate.loadedCount ++;
    [appDelegate xmlLoaded];
    [webView removeFromSuperview];
}

AppDelegate.m:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    splashVC = [[SplashViewController alloc] init];
    [window addSubview:[splashVC view]];
    [window makeKeyAndVisible];
 
    [self doAppInit];
 
    return YES;
}

The only problem with this approach is that the background application loading logic seems to occur before the web view is loaded, so there can be a pretty long delay on the transitional screen before the animation is shown. This is exacerbated in this specific app, as it requires substantial XML data from REST services. Perhaps performing this initialization code in a separate process would help.

Check out the animation and the rest of the free app here.

Gym Jones — Website Relaunch

2011 September 27
Comments Off on Gym Jones — Website Relaunch
by Alec

Prior to my trip to Europe I put a good three weeks into the relaunching of GymJones.com. Gym Jones, if you haven’t heard, is the local enigma of a gym here in Salt Lake City. Most local climbers at least know of it since it was founded by Mark Twight, one of the country’s finest and boldest alpinists. The gym focuses on performance gains through psychological breakthroughs, which sets it far apart from the typical mirror-lined, machine-packed commercial gym experience. I myself am attracted to the focus on functional fitness and mental growth, as these benefits can enhance many other aspects of one’s life.

But I digress. GymJones.com was in need of an overhaul, especially as their site has grown exponentially in popularity over the past few years. STS is a big fan of the gym, and was a natural fit for the site’s overhaul. The first stage in the project was a functional and aesthetic improvement on the public-facing website. I’d say we succeeded, especially on a (typically…) greatly condensed schedule.

The site launched on September 1, and allegedly had 10k hits in the first week. A NY Times article (with a link to the new site) on the gym undoubtedly increased that immensely. This makes the site far and away the most visited one I have ever built. Woohoo!

Be on the lookout for a revamped members site in the next few months. I’ll undoubtedly contribute to some extent — hopefully with the technical architecture and possibly the code as well. Many thanks to STS for hooking me up with a really fun project — you guys rock it, again and again!

Design: Super Top Secret, Gym Jones
Development: 95% me
Technology stack: Django/Python, MySQL, HTML5/CSS3, JQuery/javascript

Publicis Dallas

2011 July 21
Comments Off on Publicis Dallas
by Alec

A few weeks ago Super Top Secret launched another agency site for Publicis Dallas. I did about 90% of the development for the public-facing site, while a few other freelancers worked on a custom CMS and Flash-based video player.

Publicis is a huge, global advertising agency with three locations in the United States. STS had some connections with the Dallas office and we were tasked with relaunching their website, consisting of both a rich public portfolio section and email marketing capabilities. Due to internal complications, I was tasked with completing the site on a greatly reduced timescale and managed to deliver.

The site features a custom horizontal scroller which was reluctantly written from scratch as no existing jQuery library satisfied the unique requirements. It also features dozens of animations and transitions as well as client-site search capabilities. I also utilized the Yahoo! Weather API to pull in current weather information.

Stay tuned as a custom mobile-friendly version is also in the works. Many thanks to Pam at STS for her diligence and exceptional handling of the details to keep the project moving smoothly, especially when some unexpected difficulties arose.

Check it out! http://www.publicisdallas.com

First live facebook app

2011 May 5
Comments Off on First live facebook app
by Alec

I’ve been helping out local agency Super Top Secret for the past few weeks, and yesterday finished up a Facebook app for Street League, a company that puts on skateboarding tournaments all over the country. They wanted fans to be able to view the tournaments live through a Facebook app.

It’s a pretty simple app that just displays a video feed and provides a venue for discussion. Due to some annoyances with the Facebook API we had to employ some trickery to balance between capturing user “likes” and providing easy access to the video stream. There’s a basic CMS to update the status of the current feed. Everything was done with Python/Django (along with the Facebook Javascript API of course).

Check it out at http://apps.facebook.com/streetleague.

Introducing pereiraodell.com

2011 February 26
Comments Off on Introducing pereiraodell.com
by Alec

I’ve been working for the last two months on a refresh of Pereira & O’Dell’s website. It’s basically a glorified version of a typical small business website, in this case tailored for a very visually-oriented company. POD is an advertising agency based out of San Francisco.

I worked with the excellent local interactive consultancy We Like Small to develop the site. POD did the vast majority of the design, WLS managed the project, and I coded the entire front- and back-end. It’s a project unlike any I’ve done before, and I’m extremely happy with how the project turned out. Working with pragmatic, talented, and laid-back people is a joy. All parties delivered, and after numerous revisions we went live only a week past the original schedule, all while accommodating a number of additional requirements.

It will still need a few days’ effort to fix bugs, tweak the CMS, and add some visual embellishments, but is very much usable in its current state. Check it out!

Pereira & O’Dell

Update: The site is complete. We also built a version optimized for iOS (mainly the iPad). WeLikeSmall added it to their portfolio, as well, check out the write up!

Christmas Insanity!

2010 December 26
by Alec

Well, probably not the kind you’re expecting: Family drama, stress, gift anxiety, etc. No, I’m talking about “Insanity,” a game you probably haven’t heard of. It’s pretty simple. Ten holes on a piece of wood. Eight pegs; four red, four blue. Move all the pegs so that the colors are exactly switched. Pegs can only move in one direction. They can either move to an adjacent empty hole, or jump one peg of any color to an empty hole.

I picked it up and thought, gee, I could pretty quickly write a program to solve this. The game parameters were simple, yet it was a challenging enough problem that I couldn’t quickly pick it up and solve it. So I sat down with my laptop, fired up TextMate, and started hacking away. Python was the language of choice, mostly because I have a couple projects going on using it and needed the practice.Insanity

My algorithm is about as dumb as they get: Choose a peg at random, then randomly do a jump or “slide” move, if possible. I figured there weren’t that many possible moves, so it wouldn’t take that long. A few minutes of tweaking, and the program would keep getting stuck because of some poor initial moves. A little more tweaking (mostly increasing the number of tries per game) and it finally found a solution. Success!

See the code below. There’s undoubtedly substantial room for improvement, but it does the job, usually solving the problem after 5-10 minutes. I was pretty happy about the number of mistakes I didn’t make, after getting familiar with the python interpreter. A fun diversion on a snowy Christmas day.

insanity.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
import random
 
def play_game():
    won = False
    while not won:
        game = Insanity()
        count = 0
        while count < 10000:
            if game.game_over():
                won = True
                print game.log
                print "You win!"
            game.move()
            count += 1
        if game.moves > 25:
            print game.log
 
class Insanity:
    def __init__(self):
        self.holes = []
        self.pegs = []
        self.log = ""
        self.moves = 0
        self.moved = False
        for i in range(10):
            h = Hole(i)
            if h.peg:
                self.pegs.append(h.peg)
            self.holes.append(h)
 
    def move(self):
        self.moved = False
        peg_to_move = self.pegs[int(random.random() * 8)]
        r = random.random()
        if r > 0.5:
            if self.can_jump(peg_to_move):
                self.jump(peg_to_move)
            elif self.can_slide(peg_to_move):
                self.slide(peg_to_move)
        else:
            if self.can_slide(peg_to_move):
                self.slide(peg_to_move)
            elif self.can_jump(peg_to_move):
                self.jump(peg_to_move)
        if self.moved:
            self.log += self.print_board()
 
    def jump(self, peg, distance=2):
        self.holes[peg.pos].peg = None
        new_pos = peg.pos + (distance * peg.direction())
        self.holes[new_pos].peg = peg
        peg.pos = new_pos
        self.moved = True
        self.moves += 1
 
    def slide(self, peg):
        self.jump(peg, 1)
 
    def can_jump(self,peg):
        return peg.can_jump() and not self.holes[peg.pos + peg.direction()].is_empty() and self.holes[peg.pos + (2 * peg.direction())].is_empty()
 
    def can_slide(self,peg):
        return not peg.at_end() and self.holes[peg.pos + peg.direction()].is_empty()
 
    def print_board(self):
        stri = ""
        for hole in self.holes:
            stri += hole.__str__()
        return stri + "\n"
 
    def game_over(self):
        for hole in self.holes[0:4]:
            if hole.is_empty() or not hole.peg.color == "red":
                return False
        for hole in self.holes[6:]:
            if hole.is_empty() or not hole.peg.color == "blue":
                return False
        return True
 
class Peg:
    def __init__(self, color, pos):
        self.color = color
        self.pos = pos
 
    def at_end(self):
        return (self.color == "blue" and self.pos == 9) or (self.color == "red" and self.pos == 0)
 
    def can_jump(self):
        return (self.color == "blue" and self.pos < 8) or (self.color == "red" and self.pos > 1)
 
    def direction(self):
        return 1 if self.color == "blue" else -1
 
    def p_color(self):
        return "B" if self.color == "blue" else "R"
 
    def __str__(self):
        return "P(%i%s)" % (self.pos, self.p_color(),)
 
class Hole:
    def __init__(self, i):
        self.num = i
        if i < 4:
            self.peg = Peg("blue", i)
        elif i > 5:
            self.peg = Peg("red", i)
        else:
            self.peg = None
 
    def is_empty(self):
        return self.peg == None
 
    def __str__(self):
        p = "E"
        if self.peg:
            p = self.peg.p_color()
        return "%i%s " % (self.num, p,)

Four Months In: Technical Notes

2010 October 21
by Alec

Well, it’s been…

one week since you looked at me
Cocked your head to the side and said “I’m angry”

Wait, wait, wait…no, that‘s not right.

Four months!  Since I’ve been freelancing, just about anyway.  Only recently can I say it’s been going well, but yes, I’m quite busy now.  I’ve got projects going on involving PHP, Magento, Java, Android, Unity, C#, Facebook, Python, Django, Javascript, JSON, and XML, with some HTML/CSS/Javascript sprinkled in.  A lot of these I have next to no experience with, so it should make for some exciting work, provided the wtf-is-going-on-smash-head-repeatedly-against-wall moments are kept to a minimum.  Here are some thoughts from the first few months:

PHP/Magento:  I admittedly don’t have a lot of experience with PHP besides some small pages hacked together quickly in college, but playing with Magento has been pretty eye-opening.  It’s based on the Zend Framework, and is built from the ground up to be highly modular and extensible.  Pretty much everything can be overridden or replaced, and it’s all MVC-based, without really any of the hackish behavior typically associated with PHP.  I was especially surprised at the substantial usage of inheritance and other OO features.  Likely, I’ll be doing a bit more with Magento in the next few months, so we’ll see how my opinions shift.

Java/Android: Developing for devices is really fun.  The Android platform is very well documented, and playing around with the various hardware these phones have (camera, accelerometer, SD cards) is pretty cool.  I’m quickly running into a lack of third-party libraries for certain things, like physics engines, but am finding alternatives.

Freelance life: This is a common topic of discussion, and I’m still figuring out what works and what doesn’t.  As much as I want to think my time is mine to do whatever I want whenever I want, it’s simply not true.  The world revolves around the 9-5, and to a certain extent, you have to, too.  That means delaying work til after dinner isn’t always a good idea, as friends and family call or want to hang out.  I think rising early is going to become mandatory.  I can’t really complain about being able to go on mid-week climbing trips with no advance notice, though, or buying the cheapest flights due to few time restrictions.  It’s pretty awesome.

WordPress/Typo: OK, Typo sucks.  I just needed to use something better to find out.  In this case, WordPress is miles, no, light years ahead.  A migration of my personal blog may be in order.

Here’s to another four months, and way, way beyond!