ruby! rails! kids! oh my! … and other fun from terry heath
RSS icon Email icon Home icon
  • Migrations with Mongo (and MongoMapper)

    Posted on February 26th, 2010 terry 7 comments

    I’m working on an application (which you’ll get to see soon) with another guy, and he introduced some timestamps to a MongoMapper model after some of those models had already been coded. As a result, the first time I tried to visit a page with my user, I got a sweet NoMethodError, because apparently nil doesn’t implement strftime.

    There are lots of ways to solve this problem, but it’s one that doesn’t arise nearly as frequently on SQL databases (I hypothesize…) because you have migrations where you can set default values for the schema.

    When we decided to write our new app in Mongo, one thing that worried me would be data transforms down the road. How do we keep up with those? Do we just create rake tasks and run each one, noting them somewhere in a textfile? That sounds kind of awful:

    8.3
    * run rake:transform_user_emails to downcase emails
    * run rake:default_user_nicknames

    8.4
    * run rake:user:canonicalize_phone_numbers

    This gets out of hand in a hurry.

    Anyways, in my MO of looking on the first page of Google, not finding my answer, and writing something that does mostly what I want, I give you Mongrations.

    Before I say anything else, I’ll tell you that I would love forks and fixes and bug findings and I know I need to write tests – but I’m pretty sure no matter what anyone does, Mongration is going to stick.

    If you install the plugin (it needs to be a MongoMapper backed application), and change your vocabulary to use “mongration” and “mongrate” instead of “migration” and “migrate,” respectively, you have pretty much what you had with ActiveRecord’s migrations, only instead of schema changes, you just manipulate data.

    I think this is actually a fairly pure solution. While there were problems and gotchas with integrating schema changes and data changes in the same set of migrations, I think MongoMapper skirts that with the schema being solely defined in the models.

    It’s entirely possible I’m overlooking something ridiculously easy, so feel free to tell me as much if you think so.

  • Love/HATE on Heroku

    Posted on February 23rd, 2010 terry No comments

    I played a lot with Heroku yesterday, and after a good fight, got Love/HATE running on it.

    I’ve talked to people about making a public Love/HATE site, using groupings or something, but I’m not sure if I like that use case. Someone also suggested making a way to enter feelings through a webform, which I outright rejected – that you have to know how to make an SSL key (or at least follow instructions) and put a binary on your system I think are good requirements for the users I want.

    Anyway, if you want your own Love/HATE instance now, it’s easier than ever. Here’s how to do it:

    1. Sign up for Heroku
    2. Clone the Love/HATE repository
    3. Put all your users’ public keys in the public/keys directory
    4. Deploy to Heroku
    5. Done

    If you want to add more keys, you’ll need to add them locally and then re-push the application.

  • Heroku Notes

    Posted on February 22nd, 2010 terry 1 comment

    I played with Heroku a good bit today, and noticed a few hiccups. It’s entirely possible that one of these issues is due to my misunderstanding, but I figured I’d at least note them here.

    Overwriting Installed Gems

    I needed a newer version of DataMapper than was available on Heroku, so I put that in the .gems manifest. That failed spectacularly at first, because as soon as I said “require ‘dm-core’,” I got the fantastic “cannot activate dm-core [0.xx] because [0.yy] is already activated.” [Sidenote: is this something Bundler solves? Because that'd be painfully hilarious]

    But I still needed the require statements in my environment.rb, at least for local stuff. Solution? Wrap every require statement in a rescue block:

    Require statements case sensitive

    Two issues came from my magic_key_auth gem, and this was the first one I ran into. I was doing “require ‘ssl.rb’”, essentially, and the file was named SSL.rb. This works on my machine and on my work’s instance of lovehate, but doesn’t work on Heroku.

    I changed it to SSL.rb, and the file was found, and I was onto my next issue.

    Items required in your app aren’t necessarily visible in your gem

    I think this is something Heroku does to keep gems well isolated and from interfering with other gems, and all it really did was reveal a bug in magic_key_auth, but again, worth noting.

    In Love/HATE I was requiring ‘ezsig’ (from EzCrypto), and then called out to MagicKeyAuth, which didn’t require that library (even though it uses EzCrypto::Verifier). This resulted in that module not working, and authentication always being false. I bumped magic_key_auth to 1.3 and now require ezsig at the top of the SSL module.

    I figure I’ll be playing with Heroku a lot over the next few weeks, so I’ll keep things posted here.

  • Bling Bling gem management

    Posted on February 20th, 2010 terry 9 comments

    With Rails 3 and 2.3.5, I’ve been trying to use Bundler, but it’s been pretty painful so far. It’s not lightweight, and the only problem I really had with config.gem was that it had to load up the Rails environment to run, which meant if you had some code that was out in the open referencing a module or class in a gem that wasn’t yet installed, it borked (AASM did this to us). This made rake gems:install useless for lots of things.

    After jumping through the bajillion hoops and kludges to get mongomapper working, RSpec started giving me some problems with bundler, so I set out last night to make something really simple, just to manage gems, Bling.

    It’s not nearly as feature-rich as Bundler. It won’t unpack your gems or cache them, and it wants to install all gems to your system. So if those features are important to you (and they probably are to a lot of people), bling isn’t for you.

    Bling just uses a yaml file (in Rails.root, for Rails projects) to keep up with gems, and lets you specify gems, their versions, their sources, and what lib to require (if not easily guessed as the gem name).

    I bet I’ll have to add features to it as I go, but it’s solved the few problems I’ve had so far.

    To get started, just do a “(sudo) gem install bling” and then in your Rails directory to a “bling init”. Once you’ve set up your bling.yml how you want, if you have any new gems, just do a “bling install”.

    Gem info is here. GitHub is here.

  • Scheduling Jobs with DelayedJob

    Posted on February 19th, 2010 terry 3 comments

    For a new project at work, I was tasked with reevaluated our async worker system. Previously we’d been using beanstalkd with a jobs model that used AASM for persistence and kept up with when something should be scheduled (and was scheduled with a rake task). After looking at the different things available, I decided DelayedJob was a better way to go, because it involved fewer dependencies (no more cron-rake work, no more beanstalkd) and had the persistence built in, instead of our custom code.

    One shortcoming, though, seemed to be scheduling jobs. After thinking about different ways of keeping up with what jobs could be scheduled, I figured it’d make the most sense for jobs to just re-schedule themselves before execution.

    That said, I didn’t want to put that in every class that had a perform() method as a boilerplate, “reschedule myself for 24 hours,” because it’s harder to maintain and grok what jobs are scheduled, and because it’s not nearly as readable.

    Enter ScheduledJob, a mixin that gives you a run_every method on your class:

    With this, you can create a class and include ScheduledJob, and then just say “run_every 24.hours” or whatever. Like this:

    Hopefully this is helpful. I’ll need to write some tests, and see if the DJ guys want to use it on GitHub.

  • Magic SSL Key Auth Gemified

    Posted on February 18th, 2010 terry No comments

    My boss told me he really liked posting to Love/Hate using the private-key-signing authentication method, and suggested I extract it to a gem. So I did.

    You can find the gem here, and the GitHub repository here.

    In addition to the authentication block (which just traverses a directory full of keys and checks if any of them match the signature), I added a Message class which makes it a little easier to sign a request (and by “little” I mean just that – it’s probably only saving you 3 lines of code).

    I’d like to find a way to make it work with SSH-style keys as well, but this is a nice v0.1.1.

  • Spamming your IRC with Profane Weather

    Posted on February 10th, 2010 terry No comments

    At work, we’ve gone to the newest technology: IRC. I like it for a lot of reasons, like the public conversations that (ideally) make everyone, and recently we’ve started letting bots tell us things in the channel. Any time anyone checks anything into GitHub or a build happens, we get a friendly message from GitHubBot or IntegrityBot.

    Well, in a joke (and an attempt to make our workplace safer – Austin sucks when things freeze!), I decided we needed a WeatherBot. And where better to get the weather than, say, thefuckingweather.com?

    So, if you use IRC (or really whatever, and this isn’t a hard script to write at all, but it’s hilarious, so I’m posting it anyway), just change the variables and you’re all set. Here you go:

  • Love/HATE

    Posted on February 10th, 2010 terry 3 comments

    A few nights ago I was at dinner with some guys from work, and a guy mentioned that a team he’d seen had started writing things (while working) that they liked that other people were doing, and used that in conjunction with money at the end of a quarter or something to reward employees.

    I have no money to give to my coworkers, but I thought the idea of a love distribution system would be kind of fun. And, working with hilarious people, we all understood that hate distribution was just as (if not more) important.

    So, spending a morning writing and learning Sinatra and DataMapper and tinkering with HAML and banging my head over signed messages (wtf, EzCrypto and openssl – why can’t you verify something with an SSH style key!?), I give you Love/HATE.

    It’s really a developer, inner-circle kind of Twitter. You have to install some scripts on your machine and have whoever sets up the instance put your public key on the server, that’s how you’re identified and given permission to post.

    We’ve put it up on our TV, right next to CI, so we can flame (or love, but let’s be honest, it’s mostly insults) each other while watching our builds pass. It’s kind of fun, and I think has the potential to turn into a way to voice black and yellow hats before they become official. Even if not, it was fun to write.

    I’ve set things up to be pretty configurable (a buddy is supposed to be adding an IRC bot notifier…), so assuming you can run a Rack application and you’re on a *nix machine, you should be able to participate. If the readme doesn’t make sense, please let me know.

    If you’re on a Windows machine, well, I have no idea what to do about that. Sorry. If you do decide to give it a shot, let me know how you got that working (it probably won’t be hard, putting a Ruby script in your path, and figuring out how to get a key set up, but I have no idea what tools Windows guys use nowadays, so I won’t even try).

  • cc.rb -> Integrity

    Posted on February 3rd, 2010 terry No comments

    A few months ago, after upgrading cc.rb to the newest version (coinciding with our move to GitHub), CI started going really slow. The load on the single CPU machine would often go over 10. CCTray/Menu would say CI was down, when really it just took >1minute to render anything.

    We weren’t sure what was up, so after some reading, thought maybe it had to do with the number of historical builds we were keeping. So I cronjob-duct taped that to kill builds and kick off new ones nightly, but that didn’t seem to fix it.

    We decided to try the CI instance on EC2 (funny enough, on a wussier box, but we didn’t think about that at the time), and EC2 turned out not to be the solution either.

    Fed up, I switched us to Integrity, which has some nice notifiers (IRC!), a better user interface (imo), and had the possibility of being faster. After putting 5 projects on it, it wasn’t. Load was already up to 5.

    Turns out that RCov is pretty CPU-intensive, and for some of our projects we were running it for every commit. After turning that off, load hasn’t been a problem, but I liked Integrity enough that I decided to stick with it. Unfortunately, it was missing a few features I really liked, like automagic build log updating and build locking and CCTray/Menu support (out of the box).

    CCTray/Menu

    Nobody on CCTray has made this work yet, so that’s a little misleading, but the CCMenu users have had success. There’s a gem called integritray that’s supposed to provide support with just a config line, but that wasn’t intercepting the requests correctly, so I ended up just dumping the integritray code into Integrity’s app.rb.

    Build Log Auto-Update

    So part of this I did really well (I think), and part of this I did terri-bad (definitely). First up, the way the build gets called is with IO::popen, which is all fine and dandy, except the build has to finish before output gets written to a field on a DataMapper Build object. This doesn’t work for live updating.

    You could probably do all of this by just editing the build command per project, but I wanted to get my hands dirty with Integrity, so I opened up lib/integrity/builder.rb and changed the run method to this:

    That’s going to do a few things. First, it’s going to write the output to stdout (for future consumption) as well as a build log named by the id of the build, and it’s also going to maintain the exit status from Rake (instead of tee, which is always going to be 0). I’ve only tried this on Bash, so $PIPESTATUS might not work if you’re not using that shell. Sorry. Next, I just gave the Build model a default value for output, so the method looks like this:

    I added a cronjob that deletes all of the old build logs nightly, because after they’ve run, they’re saved to the Integrity database.

    Build Locking

    One of the nice things about cc.rb was that it didn’t try to start a new build for a project if one was already running. This might not be a problem for lots of projects, but with Rails projects with fixtures (ugh) and migrations, it can cause db deadlocks. I decided to add a rake task (that we use for all our Rails projects now) for Integrity to use locking. Here’s what that looks like:

    So now doing a rake integrity:run will guarantee only one of those tasks runs at once. Note that it doesn’t guarantee to run the calls in order, and it’s possible that a build will run on a codebase that’s been updated since it started (I think I might be able to avoid that by loading up the Rails env before looking at the lock), but at least it prevents db deadlocks.

    I haven’t added any of this as a pull request or anything to Integrity, because it’s not that polished yet, but feel free to pull whatever you see if it helps out.