How Sinatra, Backbone and Mongo Sucked Up Two Weeks of My Life
A couple weeks ago ArsTechnia ran a story stating that the Express versions of Visual Studio were going to be super stripped down. As a friend and I discussed on Twitter, I made the comment that the story made me want to learn Ruby.
Not long after that, Scott Hanselman (best employee at Microsoft?) corrected the article for us:
What I did:
Nevertheless, I stood by my word and decided to learn some Ruby, and I knew just the app to write. A few months back at Nebraska Code Camp, Scott Hanselman gave a talk on how to control the flow of data for your life. One of the things he mentioned was coming up with 3 things to do each day. The goal being that you can cross these 3 things off and consider your day a success.
This resonated with me. I’ve created more To-Do lists than I know what to do with. Most of the time I abandon them because I overload them with dozens of items I need to do, and when I don’t get those done, I feel as if I’ve failed.
The other reason it resonated with me was what I’m calling “The deserted island principle.” If you were stuck on a deserted island, what 3 _____ (books, albums, friends etc) would you bring?” It helps you focus. I have a lot to do today, but what are the 3 most important things?
Why I did it:
So that set me in motion. I was going to make a Ruby site for doing 3 tasks a day. If nobody ever used it, I still could, and it would be fun to learn. I’ve spent my entire professional life in the Microsoft realm. It started with MFC C++, then progressed to .NET. I like Microsoft technologies. I enjoy coding in .NET, but lately I had become a little dissatisfied with the .NET community. Too many people being spoon-fed from Redmond.
I’ve read enough to know that some of what we’re getting in .NET mirrors what Ruby first. For example, everyone using NuGet is using the .NET version of Ruby Gems (which is using the programming version of Linux’s apt-get or yum.) In fact, pre-Nuget, there were actually .NET packages in Ruby gems — it’s how I installed Mongo & the C# driver the first time.
In addition to things like that, frameworks like SimpleData have a remarkable ActiveRecord feel to them. NancyFx is so named because it derived from Sinatra (and Frank’s daughter was named? You guessed it, Nancy.)
Additionally, there seems to be some hatred for Ruby in the .NET world. I’m guessing it’s like the C++ world calling C# “VB with semicolons” when it first came out (that wasn’t a positive comment either.) I am a bit of a rabble-rouser, so I thought I could learn some Ruby and show the .NET guys that it didn’t instantly make me a bad programmer — I’ve been bad for years!
How I did it:
Friday Night/Saturday Morning
I started by installing Linux Mint in a VM, then got Ruby installed and running. I created a couple really basic Ruby projects, that did “Hello World” type stuff. Then I checked out Rails For Zombies which is a really well done class teaching the basics of Rails in a series of 5-10 minute videos and coding exercises.
By the time I got that far, it was Saturday afternoon, and I took a break. (Unfortunately, I took a much longer break as my cable modem decided that would be a good time to die.)
Saturday Evening/Sunday Afternoon
After the HelloWorld type apps, I thought I was ready to start working on my site. I fired up some Ruby scaffolding (which I love!) I got some basic routes going, and even got Mongo set up using MongoMaper.
Despite loving the scaffolding on Rails, I quickly realized that an entire Rails app just for one page was probably a bit overkill. I had looked at Sinatra about a year before, and thought maybe it could do what I needed. So I scrapped all my Rails code and started a brand new project for Rails. By the time I went to bed, I had basic GET and POST methods working.
Monday (Memorial Day)
So by now, I had a basic site up. It was completely unstyled, black text on a pure white background and 3 bullet points for my tasks. That was by design, though. I wanted to get the backend working as good as I could, so that when I started making UI changes I would know where the problems were.
I spent the better part of Monday playing with erb files, and trying to get edits up and running. I had a basic, though still largely unstyled, website by the time I went to bed.
Tuesday
Tuesday night I decided to try and do some fancy “Edit in place” for my tasks. No need to go to separate pages. This is 2012, and everybody is writing a single page app, so why can’t I? This didn’t go nearly as well as I had hoped. My JavaScript skills are pretty pathetic, so I went on the search for plugins. I found a couple, but both of them wanted to dictate how they sent data to the server, and it wasn’t how I wanted them to.
For starters, I wanted them to POST new tasks that were created and PUT existing tasks. I found one that only wanted to PUT and one that only wanted to POST.
Wednesday
During work on Wednesday I talked to our front end guy (who thankfully sits right beside me.) We have been doing some Backbone.js and Handlebars for some projects at work, but I didn’t really know what those were about. As I talked to him about how to do my editing in place, he directed me to Backbone, and honestly there wasn’t a better package to meet my needs. It wasn’t that it really handled the editing in place (I still had to copy some JavaScript from the Backbone Todo project), but it made interacting with my ReSTful back end so simple. So that night, I sat down and worked through some tutorials, and created my first Backbone model, view and collection.
It was pure joy.
I went to sleep knowing that this new JavaScript library could detect what calls need to be made, and could keep my UI in sync with my service without a lot of worrying about URLs and paths.
Friday & Saturday
It was the weekend again before I could play around with my project at all. Friday I spent getting Bootstrap going for my styles. The site was starting to take shape and I was tired of staring at my ugly page. I had used Bootstrap before on another project, so there wasn’t the learning curve there on this project. Which made it nice to get up and running.
Friday night I also spent time looking at Ruby’s omniauth. One thing I hate is dealing with user management. I don’t want to salt passwords, and have registration forms, and worry about a “forgotten password” flow. After all, I just want a to-do list, let someone else handle the authentication.
Thankfully, OmniAuth is stupid-simple. I was up and running in a matter of minutes (maybe 30.) The one hangup I had was that I didn’t actually register my app on Twitter and Facebook to get API keys, so I kept getting unauthorized exceptions, but that was easy to rectify (and was in no way, OmniAuth’s fault.)
By mid-day Saturday I had the ability to sign-in by either Twitter or Facebook and tie tasks to a specific user.
One issue I did have, however, was I had no UI element showing me if I was signed in or not. This lead to a few problems, as I couldn’t tell if there was an error pulling tasks from the DB, or I just wasn’t logged in.
I spent a couple hours trying to get my session[:user_id] parameter to work on my html page with no luck. By now I had spent WAY too many hours on this, and I was tired.
Sunday
The issue with the session and the HTML file was this. By default, Backbone uses the syntax <% vairable name %> to indicate place holders that the Backbone view is supposed to replace. That was fine when I just had a plain HTML file. However, to handle the session, I needed some information from my Ruby server, and I wanted to use an erb file, but it used the exact same syntax.
So I ran into the issue of Ruby not knowing what to do with my Backbone placeholders. Unfortunately, this took a lot longer than I wanted to. I finally found a blog post that showed how to use Moustache type syntax for my Backbone place holders. I don’t remember the blog right now, but it’s simply this regex:
_.templateSettings = { interpolate : /{{(.+?)}}/g};
So now I could have an erb view that has something like <% if session[:user_id] %> on one line (for the Ruby server) and {{taskName}} on another line (for Backbone.
Monday
The last task I had was to get a pre-auth page up and running, as well as some static content (such as an about page.)
The main reason I wanted a pre-auth page was it was actually possible, up until this point, to not be logged in and create tasks. This was fine, except everyone shared the same tasks, because the user id was null. (There was also a bug in the back end that I found that kept creating new tasks when it shouldn’t have.) So by limiting the task creation to only people that are signed in, it greatly simplified the troubleshooting.
After that was wrapped up I pushed one more time to my production site (something I skipped over in this blog) and hit it inside my VM and outside, using Chrome and Firefox on both platforms, just to make sure it worked.
Work in Progress
I’m sure it’s not 100% yet, but I decided to write the post and make it public because too often we get hung up on something not being perfect. I want to make sure I ship.
So that’s how I spent just under 2 weeks playing with Ruby, Mongo, Backbone and JavaScript. In all honesty, I’d say a good 70% of my time was spent working on the browser side, an area that I knew almost nothing about.
I’m really glad I spent two weeks doing it. I feel like I have a better (but still small) appreciation for Ruby and some of the libraries that it uses.
So without any further words, let me introduce (at it’s temporary home):
One last caveat:
I wrote this blog post Monday night. I thought I had tested it on Heroku, but apparently, I didn’t. When I did I quickly noticed I was losing sessions rather quickly. Turns out the best way to work with sessions in Sinatra on Heroku is to use Rack::Session::Cookie. To the best of my knowledge it is working now!
Update:
As of June 13, I have made the Github repo public. Head on over and fork the code, or send me your code review issues.