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...