Photo-1 Photo-2 Photo-3 Photo-4 Photo-5 Photo-6

@brentmc79

@brentmc79

Full-time web developer. Part-time smart ass.

I'm Brent Collier.

After a year and a half as an engineer on Twitter's Trust & Safety team, I'm looking for my next gig. Contact me if you know of something interesting.

#

Backbone.js + Rails 3.1 Asset Pipeline

Posted on 09/24/2011

I was working on a client app with a very js-heavy front end and I thought it would be a perfect opportunity to take a dive into Backbone.js. Unfortunately it didn't start off as smoothly as I had hoped and since Google was of minimal help while wrestling with these problems, I thought I'd document my troubles in hopes that I might help someone in a similar situation.

I started off following this tutorial by James Yu. I first downloaded backbone.js and included it in the app. Then I set up my directory structure under /app/assets/javascripts/backbone. Finally I copied the basic controller/model/views from the tutorial and tweaked them to work with an existing Rails controller in the app.

I then loaded the page in the browser and saw this in the js console:

Uncaught TypeError: Cannot call method 'extend' of undefined
    App.Views
    (anonymous function)
Uncaught TypeError: Cannot call method 'init' of undefined
    (anonymous function)
    jQuery.extend._Deferred.deferred.resolveWith
    jQuery.extend.ready
    DOMContentLoaded

I soon realized that I was missing underscore.js, a dependency of Backbone. So I downloaded it and added it to the app.

Reloading the page gave me another similar-yet-different error in the js console:

Uncaught TypeError: Cannot call method 'extend' of undefined
    (anonymous function)

It was referring to the following line in my backbone notes controller:

#app/assets/javascripts/backbone/controllers/notes.js
App.Controllers.Notes = Backbone.Controller.extend({

Backbone.Controller was undefined. WTF? This came directly from the sample code, so it should work. Right? I guess not.

A little Googling and browsing of the Backbone docs told me that I should change Backbone.Controller to Backbone.Router. Without digging through the Backbone repo history, I can only assume that this is due to an API change that hasn't been reflected in the tutorial. Once that was done, the error disappeared.

After that I spent some time fighting with the Rails Asset Pipeline and loading the Backbone files in the correct order. Unfortunately my attempt to reproduce and document those issues was unsuccessful. I think the problem was mostly due to me explicitly requiring the Backbone files, but in the wrong order. For some reason I just don't like using require_tree on the root js directory, but whatever, it seems to work fine in this case.

Here's what my js directory ultimately looked like:

|~app/
| |~assets/
| | |+images/
| | |~javascripts/
| | | |~backbone/
| | | | |~controllers/
| | | | | `-notes.js
| | | | |~models/
| | | | | `-note.js
| | | | |~views/
| | | | | `-index.js
| | | | `-application.js
| | | |-application.js
| | | |-backbone.js
| | | |-underscore.js

And here's my application.js:

//= require jquery
//= require underscore-min.js
//= require backbone.js
//= require_tree .

Pretty simple.

I started this blog post expecting to document my troubles with the Asset Pipeline, but in the end there didn't seem to be any. It was late, maybe I was tired. Who knows? What I do know is that when I was searching for info on using Backbone with the Asset Pipeline, I didn't find much.

Next I'm planning to expand my views and introduce some sort of templating library. Keep an eye out for another post around that...

#

Sass'd Bootstrap with Rails 3.1

Posted on 08/31/2011

Update: Sass'd Bootstrap Even better

bootstrap + sass

I saw Twitter's Bootstrap and thought it was awesome. Then I saw that somebody had ported Bootstrap over to SASS and I thought that was even more awesome. Finally, I thought hey let's crank the awesomeness up to 11 and use that sassy Bootstrap in my Rails 3.1 app.

It went something like this...

Clone the SASS fork of the Bootstrap repo

git clone https://github.com/jlong/sass-twitter-bootstrap.git

Then copy everything in the lib folder (scss files) over to your rails app.

cp sass-twitter/bootstrap/lib/*.scss path/to/railsapp/app/assets/stylesheets

By default Rails includes all of the file under the stylesheets directory, so I opened up railsapp.dev to see if it would magically work without any intervention on my part.

BOOM. Of course not.

Sass::SyntaxError: undefined variable: "$baseline".
    (in /path/to/railsapp/app/assets/stylesheets/forms.scss)

I figured it wouldn't be that easy, but it was worth a try. Clearly things weren't being required/included in the proper order which was leading to this undefined variable error. If you've used Rails 3.1 then you know that the vanilla application.css file contains a few "require" statements like so:

/*
 * This is a manifest file that'll automatically include all the stylesheets available in this directory
 * and any sub-directories. You're free to add application-wide styles to this file and they'll appear at
 * the top of the compiled file, but it's generally better to create a new file per style scope.
 *= require_self
 *= require_tree . 
*/

Including everything in the stylesheets directory by default is nifty and all, but I prefer to explicitly include each of my stylesheets, so I removed require_treeand then explicitly required bootstrap. Since bootstrap.scss is nothing but @include statements for the other scss files, so it's the only one you need.

Once that's done, you should be good to go. Just refresh your browser and bask in its sassy, bootstrappy glory.

#

Override an AR default_scope

Posted on 06/08/2011

Say you've got a Thing class and your app uses soft deletes, so maybe you've got a default scope like so

default_scope where(:active => true)

and you want to find Thing records that have been (soft)deleted, so you try this

Thing.where(:active => false).all

which returns this

[]   #sadface

What gives?

Well, your default scope hold precedence over your where condition, so what you need to do is this

Thing.unscoped.where(:active => false).all

Using the unscoped scope returns an AR::Relation without the default scope, allowing you query for whatever you want. Enjoy.


Update

Or, as it turns out, you can create a scope that negates the default scope, like so

class Thing
  default_scope where(:active => true)
  scope :inactive, where(:active => false)
end
#

Using link_to in a controller *gasp*

Posted on 05/16/2011

Yeah, I know it kind of breaks the MVC pattern, but whatever. Its not something you'd want to do all the time, but in the rare instance that you'd like to generate an anchor tag from within a controller, try this:

ActionController.helpers.link_to("Click Me!", awesome_path)

Chances are, whatever you're doing could/should probably be moved into a helper method instead of doing it in the controller, but that's up to you.