#323 Backbone on Rails Part 1 pro
In this first part of a two part series you will learn basic Backbone concepts including models, collections, routers, views and events. The backbone-on-rails gem is used for Rails integration with the asset pipeline.
- Download:
- source code
- mp4
- m4v
- webm
- ogv
Backbone and Rails is an awesome combination! Glad to see Backbone here on RailsCasts.
Another gem worth reviewing is backbone-rails. (https://github.com/codebrew/backbone-rails)
The scaffold generator of backbone-rails creates ready-to-run routers/models/collections/views/templates.
Thanks for mentioning this. I was debating between backbone-on-rails and backbone-rails, both are great projects. Went with backbone-on-rails because of the simpler generator was easier to build off of.
How to use Handlebars instead of eco in rails ?
Is there any book/s about Rails + Backbone best practices?
Thoughbot has a pdf that I have been working through.
https://workshops.thoughtbot.com/backbone-js-on-rails
Ditto. Thoughtbot PDF is well worth the coin.
Derick Bailey also has a great list of resources with lots of books, blogs and videos.
Not specifically with Rails, but I highly recommend reading anything by Addy Osmani:
https://github.com/addyosmani/backbone-fundamentals
http://addyosmani.com/blog/understanding-mvc-and-mvp-for-javascript-and-backbone-developers/
also check out joey b's backbone screencasts.
his are paid screencasts as well. both ryan and joey's are excellent. happy to support both guys.
I recently just finished a series that walks through building a scalable Backbone application layer by layer. It introduces a lot of patterns and concepts for building large Backbone applications alongside the Marionette framework. Marionette removes a ton of Backbone boilerplate and gives you application components you can leverage.
Whenever I watch or read other tutorials there is always a ton of misinformation, zombies being created, or ridiculous amounts of boilerplate code. So I've been working to show other Rails developers how to avoid these pitfalls and solve common problems.
Marionette is worth looking into regardless if you're developing with Backbone. It's site is here: MarionetteJS and you can find the series I've put together here: BackboneRails.com
since i have started using backbone, i've gravitated over to Sinatra.
The video is slightly cut-off at the end. Also the backbone-on-rails link in the show notes is pointing to another lib on github.
P.S. Great job as usual. Was meaning to play with backbone.
Fixed the link and I'll look into the cut-off issue. Thanks for letting me know about these.
Awesome job! You have a knack for distilling a complex (or cumbersome) process into simple pieces.
Thanks for pointing out bind has changed. I just upgraded a site and ran into that... and for pointing out there's a third (context) item to pass into a backbone event - never knew that was there - although I'm still not sure what it does. Maybe explain that in part 2!
Thanks Ryan. I was wondering if you had any tips for using assets in the JST templates?
Good point, I'll look into this and consider covering it in part 2.
Hey Ryan,
it's about time! Thnx a lot for this.
I think a comparison off
Knockout, Spine and ember.js would be also very interesting!
There have a much simpler syntax then backbone.js I think AND,
coffee script (spine.js) is fully "supported".
The only thing I ask me all the time, which technology has a future, not all can coexists or for me at least, it doesn't make sense.
What's your opinion on this, have you already checked out other frameworks?
cheers
I am working with Spine and I have to tell you: it is amazing the combination Coffee + Spine.
Spine is write in Coffee and it is very simple to understand its source code, but I am a bit afraid about Spine's future, it doesn't seem as active as Backbone.
Underscore is a nice lib, but I think if you are using Coffee, Underscore becomes a kind of useless.
Ryan, talk about Spine too, it deserves.
Here is underscore coffee. Is that what you were looking for?
https://github.com/jashkenas/coffee-script/blob/master/examples/underscore.coffee
I do hope to cover other JavaScript libraries such as Knockout, Spine, and Ember in the future. Not certain when or in what order. Thanks for the suggestion.
Angular.js is also interesting...
I've been working a lot with Spine lately, and it's very nice. There's a
spine-rails
gem that makes integration really easy.What's about batman.js? :-)
Made by the shopify guys and looks very interesting!!
Unfortunately, there are not very much good tuts/videos out there.
A whole series about JavascriptMVCs would be absolutely awesome!
You really have stepped up your game by branching into these new technologies. I for one find this screencast invaluable. I have watched numerous screencasts, paid and free, and this was the easiest to grok. Keep up the great work and I'll keep paying you monthly :D
Looking forward to the Spine, KnockoutJS and Ember screencasts.
I would also like to know what you would personally invest time into learning for the future? It seems that it's a toss up between Backbone and Ember
Backbone is more mature - there are lots of online videos, blog posts, and example apps for BB - not so much for Ember. Right now Ember also lacks support for routing and persistence.
I agree, it was the first screencast that made me easily understand BB. Great job Ryan! Would be great to see a Ember screencast too!
Thanks Ryan, Backbone and Rails is indeed an awesome combination.
I was wondering if you could provide the coffee script code in javascript code?
Great episode -
Why do you have to pass both params[:id] and params[:entry] to the update action in the entries controller?
I'm calling
Entry.update
(class method) so it has no context of the entry record I'm trying to update, which is why it is necessary to passparams[:id]
to it. Theparams[:entry]
contains the attributes that will be updated.Way cool Ryan.
How about doing at least a two part series on Twitter Bootstrap? Simple form 2.0 has built-in support for it. It is great for people like me who are programmers but are design challenged :)
I hope to cover Twitter Bootstrap in the future, thanks for the suggestion.
Thanks heaps another marvelous cast
While following along I had trouble formatting the coffee script correctly in textmate any ideas?
Cheers
Dave
One thing i would REALLY like to know: With all these really nice client side mvc frameworks popping up, what the heck do we do about making our app's content searchable/crawlable? I really have not seen much insight into this problem.
Since most (all?) of the web crawlers don't use javascript, do we REALLY have to design separate pages for the spiders?
You can do a lot with noscript tags and to make sure pages behind js links are crawled, you can include their urls in a sitemap and submit it to google, etc..
I wrote a couple of articles and gave a talk on this last year, specifically with backbone:
http://lostechies.com/derickbailey/2011/09/26/seo-and-accessibility-with-html5-pushstate-part-1-introducing-pushstate/
http://lostechies.com/derickbailey/2011/09/26/seo-and-accessibility-with-html5-pushstate-part-2-progressive-enhancement-with-backbone-js/
and
http://lostechies.com/derickbailey/2011/10/06/seo-and-accessibility-with-html5-pushstate-part-3-the-video/
I get an exception thrown when I start dealing with the routers. I'm not going to ruin the forum by pasting my (exhaustively long) trace in here, but I am getting the following message: Error: Parse error on line 7: Unexpected 'TERMINATOR'. Can anyone point me in the right direction? This seems like a CoffeeScript thing that I'm just lost on. Thanks in advance!
Yeah, really check your CoffeeScript formatting / indentation. I had a couple of those. I had to turn on soft tabs.
i'm having the exact same issue as @zafriedman; so should we be working where tabs are as spaces when using coffeescript? rather frustrating as i've always had everything of mine setup where tabs are tabs and not interpreted as spaces.
Thanks for mentioning that. It's useful even over a year later...
I think it would be worth to mention ExtJS 4 / Sencha Touch 2. It is more comprehensive and powerful than Backbone. It uses similar approach - client side MVC but Sencha have also validators, a lot of widgets and the killer app - Sencha Designer 2, graphics IDE for fast building the whole application (see: http://vimeo.com/36420727) In all such solutions Rails can be narrowed to be just RESTfull server...
Hey! Thanks for the link to Sencha Designer 2. I have read a lot about Sencha Touch 2 in the last month. It looks very cool!
Woah, backbone.js is like a completely different framework from rails.
Following this tutorial felt like going through a Python tutorial, I don't understand anything. hahah :D
I need to look up how backbone.js work or what its purpose is because I don't know anything about it.
Python is very similar Ruby. Yes, Backbone and Rails a very different. As they should be, Rails and Backbone are for two different purposes.
I figured. I have absolutely no idea what the purpose of backbone.js is; it's what I'm looking into at the moment.
I really liked this railscast, but i'm wondering if can be the backbone/eco part easly separated from rails project and compiled to make an external client?
Just a suggestion to everyone here:
This tutorial is very much geared towards a particular way of using backbone on rails. (Understandable since this is a railscast)
I would suggest learning backbone yourself as a standalone html and js served out of public and communicating with your restful resources first, that way you can learn more about things like modularizing your app vs namespacing etc.
learn backbone, then backbone on rails.
Thanks Ryan for the episode.
If you will be covering KnockoutJS (which is currently my preference after evaluating most of the frameworks) then you may want to take a look at knockout-rails gem.
Simple screencast that demos validations part of it:
http://blog.approache.com/2011/12/knockoutjs-validations-video.html
(it went into Ruby5, so seems like people liked it).
Cheers.
i really can't see the benefits of using this kind of libraries inside rails. i mean, if i had to build something from scratch and have to structure the app, so maybe there something like backbone.js will be helpfull.
but i don't see the need of backbone.js inside rails since ror is already well structured and all the JS stuff can be fully served with jquery (or similar)...in fact, what i see here is backbone is complicating the "fun" of programming on rails.
...do im right? or i'm missing something? please, somebody help me to understand...
Well actually, BackboneJS serves a different purpose than jQuery. With jQuery - your large web application can get really messy and difficult to maintain. Frameworks like Backbone, Ember, Spine, Batman etc provide architecture, organization and convention to your client side code as well. Just like Rails provides all these things to your server side code.
What about Knockback http://kmalakoff.github.com/knockback ? It is a hybrid of Backbone and Knockout, seems to take the best parts from both.
Can someone help me understand how to make this screencast work with monodb as my database while using mongoid. This is what I am seeing.
When I create a new entry via the console, similar to how Ryan did it in the video 'entry.create' , rails adds that entry just fine. Below are is my Ruby Log and my javascript headers log from Chrome Inspector.
Ruby Log
Started POST "/api/entries" for 127.0.0.1 at 2012-02-12 17:31:24 -0600
Processing by EntriesController#create as JSON
Parameters: {"name"=>"Heather", "entry"=>{"name"=>"Heather", "action"=>"create", "controller"=>"entries"}}
MONGODB w_market_development['system.namespaces'].find({})
MONGODB w_market_development['entries'].insert([{"_id"=>BSON::ObjectId('4f384bcc504b9348be000003'), "name"=>"Heather"}])
Completed 201 Created in 11ms (Views: 2.4ms)
Headers Log
Request URL:http://0.0.0.0:3000/api/entries
Request Method:POST
Status Code:201 Created
Request Headers (14)
Request Payload
{"name":"Heather"}
As you can see it posted fine. Now let me show you an update via the 'entry.save()' example Ryan showed us.
Ruby Log
Started POST "/api/entries" for 127.0.0.1 at 2012-02-12 17:34:25 -0600
Processing by EntriesController#create as JSON
Parameters: {"_id"=>"4f38152c504b9345dc000005", "name"=>"Bloip", "winner"=>true, "entry"=>{"_id"=>"4f38152c504b9345dc000005", "name"=>"Bloip", "winner"=>true, "action"=>"create", "controller"=>"entries"}}
MONGODB w_market_development['system.namespaces'].find({})
MONGODB w_market_development['entries'].insert([{"_id"=>BSON::ObjectId('4f38152c504b9345dc000005'), "name"=>"Bloip", "winner"=>true}])
Completed 201 Created in 12ms (Views: 2.7ms)
Headers Log
Request URL:http://0.0.0.0:3000/api/entries
Request Method:POST
Status Code:201 Created
Request Headers (14)
Request Payload
{"_id":"4f38152c504b9345dc000005","name":"Bloip","winner":true}
As you can see when I complete the 'entry.save()' on a current entry, which should be an update, the json is showing a POST instead of a PUT which mongoid is doing nothing with and the DB shows no changes. After googleing I found the following articles but nothing really helped.
link
link
I hope someone can help.
Take a look at my blog post here http://createbycoding.com/2012/02/getting-backbone-js-to-sync-with-rails-and-mongoid/. I had a similar issue a few months ago.
Thanks for covering this, Ryan. It's a bit of a divergence from the beaten path with Rails, but I think this is the future of web application development.
I've spent quite a bit of time coming up to speed with BB lately, including a 2 day training course with the Gaslight Software guys (I'm not affiliated with them: I highly recommend their course).
Initially I struggled with the fact that using BB (or any of the other similar libraries) means writing a lot more code. It's simply more complicated, especially when dealing with data persistence. Writing basic CRUD operations in plain Rails is pretty straight forward. Involving BB in CRUD is a lot of additional work.
My "ah-ha" moment came when I deployed my first BB/ Rails app to a development server. The performance was amazing. Making JSON requests via AJAX in the background (especially if you're caching) is so much more performant that doing page requests. And, pushing a lot of the application logic to the client is a big win in terms of server load.
I've come to the conclusion that BB is really amazing for client facing front end stuff where performance is a concern. It's less useful for backend admin stuff where simple Rails based page requests provide adequate performance.
@Elliot Larson, I think you've nailed it.
What a great tutorial! This makes me want to use backbone to improve the responsiveness of my more complex pages. My biggest concern is how to test all this javascript. It leaves me feeling exposed to brokenness.
Here is a series of articles on testing BackBone apps.
When I was going through the RailsCast as described above. I was using the entries controller that Ryan put together. After much searching, copying, pasting, and retrying I found that I need a completely new Controller set up. Below is what I originally had.
This is the Controller code the fixed the issue for me.
Thanks All!
Travis
why backbone submit with double params?
It's not Backbone submitting double parameters. It's rails duplicating the parameters so that you can do:
Entry.new(params)
or
Entry.new(params[:entry])
When I call entries.create my Rails app logs a GET request to /api/entries instead of a POST with params. Saving an updated entry works just fine.
I'm even getting this behavior running the railscast code from github.
Should I be using a different server than webrick?
I am seeing the same behavior when running thin. Did you ever figure it out?
rails (3.2.2)
backbone-on-rails (0.9.1.0)
Was using
Chrome 19.0.1061.1 (Official Build 125213) dev
when this was happening. Everything works fine on Safari. This is all on a Mac BTW...I think there are a couple of
.js.coffee
files that have a.rb
extension here.nice tutorial!
but i can't initialize the router. i get an error telling me that "Bb.Routers.Entries is not a contructor". (my app is called Bb instead of Raffler.) i suspect this is related to load order, but get find a way to fix it.
file bb.js.coffee:
file entries_router.js.cofee:
file application.js:
gem versions:
backbone-on-rails (0.9.1.0)
rails (3.2.1)
coffee-rails (3.2.2)
figured it out. it was problems with indentation, which meant that the code which was supposed to be in init() was actually outside the method, and was being called before the router was loaded. small gotcha for someone not used for coffeescript.
Hey Great screencast Ryan! I have a question, in the view, there is some syntax I don't understand. What is JST[]? Is that using the JST library? I'm trying to understand how backbone knows where and how to load the external template files. Any insight you could give on this would be VERY helpful.
Thanks!
Did you figure this out? I'm having the same problem...
Thanks for the great screencasts, Ryan! I found your explanations very helpful.
I am having a bit of a problem with a slightly more complicated variation of what you did for the Raffler application. I am trying to make a small "one-page" blog application, where posts can be commented. So far, I can fetch comments in a Collection, but I find it difficult to understand the strategy when to fetch, and how to update the posts index view when new comments were made.
I tried a first project template here: https://github.com/mulderp/backbone_testapp
Thanks for sharing some thoughts or feedback, if possible!
I would also be curious on thoughts how to do this TDD if possible...
I seem to be having issues, I am getting
Error: Parse error on line 2: Unexpected 'INDENT'
...raffler/app/assets/templates/entries/index.jst.eco)
I literally cut and paste the code in. Using rails 3.2.2, coffee-rails 3.2.2 I must say I am beginning to despair if it takes 4+ hours to get Hello World working with a railscast that is less than 30 days old
Raffler
<% for entry in @entries.models: %>
<%= entry.get('name') %>
<% end %>
I seem to be having issues, I am getting
Error: Parse error on line 2: Unexpected 'INDENT'
...raffler/app/assets/templates/entries/index.jst.eco)
I literally cut and paste the code in. Using rails 3.2.2, coffee-rails 3.2.2 I must say I am beginning to despair if it takes 4+ hours to get Hello World working with a railscast that is less than 30 days old
Raffler
<% for entry in @entries.models: %>
<%= entry.get('name') %>
<% end %>
I have the same issue. Did you get this resolved? I can't find an indent error any where in my code.
I'm having the same issue.
Did you manage to fix it?
p.s. I'm trying this on a windows machine.
It looks to be a known issue: https://github.com/sstephenson/eco/issues/29
I'm looking into alternatives to eco on windows
I just used straight ejs instead of eco.
It means the template looks more like:
It now works for me. But no nice coffee script templates.
Download node.js and add it to your path (this is done automatically if you use the msi installer). After you may need to restart your computer before it will work.
Another odd thing, the generated application.js seemed to be escaping the '/' with '//' I had to manually fix that. HTH someone.
to get the value for each entry he used this:
<% for entry in @entries.models: %>
<%= entry.get('name') %>
<% end %>
that didn't work for me, I modified it to this one:
<% for entry in @entries.models: %>
<%= entry.get('entry').name %>
<% end %>
and it works,
Any Idea?, I want the sipler code rather than the code I came up
Thanks
After two days of trying to figure out why my app suddenly broke (it used to work before), I found your reply here and I have the exact same issue!
Before this worked:
But after some more working on the app, and updating gems (which I suspect broke things), I had to replace it with this to continue working:
I suspect something changed in a recent Backbone.js update or it has something to do with Rails'
include_root_in_json
options (but I tried bothfalse
andtrue
, no dice).I don't get the "home page" alert dialogue at 5:35. Note that I did get the "Hello from Backbone" alert at 3:45.
Any help will really be appreciated. I am running rails 3.1.2 in Ubuntu 10.04.
Also note that I had to include the gem "therubyracer" to get the server running at the start (I was facing the issue similar to https://github.com/rails/rails/issues/2963)
Below are the relevant parts of the code and the error trace I get in the console.
app/assets/javascripts/routers/entries.js.coffee
app/assets/javascripts/raffler.js.coffee
The error trace I get in the console is:
In entries.js(5): Uncaught ReferenceError: Raffler is not defined
In entry.js(5): Uncaught ReferenceError: Raffler is not defined
In entries.js(23): Uncaught ReferenceError: Backbone is not defined
In index.js(17): Uncaught ReferenceError: Backbone is not defined
In raffler.js(9): Uncaught TypeError: Undefined is not a function
centaure, I had the same problem and figured it out.
Your application.js file must be like this: