going to be talking a lot about Javascript MV* or MVC frameworks. I’ll use the terms interchangeably. Poll: how many have used a JS MV* Framework including Backbone, Angular, Ember, Knockout, or something else? Backbone? Angular? Ember?
• Templating (Handlebars, Mustache, jQuery Templates, etc) Javascript MV* Frameworks We need some structure around our javascript applications, otherwise they get nuts. Javascript frameworks help other developers (and future-you) to recognize and maintain the application.
that are out there is TodoMVC. It’s the result of a collaboration of lots of different developers who have all built an implementation of a simple TODOs app in around 20 different frameworks.
Data store is local, non-flaky, & dumb (i.e. unrealistic) In order to illustrate how frameworks differ from libraries, let's look at TodoMVC... What is it? - The same app (todos) built in ~20 different js frameworks (Backbone, Angular, Ember, Knockout, etc) - Intended to be instructional & portable - TodoMVC is good, but it's not the whole picture - only deals with views & controllers - data store is local, non-flaky, & dumb (not very realistic) [as opposed to REST: validations, relations, collaboration] This focus on views & controllers (and it leaves out the back-end) is consistent with most of the javascript frameworks out there: most focus on data-binding and routing, punt on persistence.
you are familiar with this traditional application architecture from Rails. We have views that display the user interface, controllers that respond to user actions, models that provide an object-oriented abstraction for our data store, most likely a database.
Server Javascript MVC applications follow a very similar paradigm, with views, controllers, models, and a data store, with one key difference--the data store is typically a set of web services, which can be implemented in Rails. So you end up with an app-within-an-app.
Postgres MongoDB Rails JS Application Architecture On the client side we need to do all the same things we do on the server side, whether we realize it or not. The first way you can do this is the way we were all doing this 5 years ago. It used to be the only way to do it.
Postgres MongoDB $.html $.live $.ajax Restful API Application Architecture Rails JS then update the correct element using $.html This works, but it’s a mess, for several reasons...
Postgres MongoDB $.html $.live $.ajax Restful API Not testable Spaghetti Code Callback Hell Non-DRY Application Architecture Rails JS not DRY, so you can’t re-use components...
Postgres MongoDB $.html $.live $.ajax Restful API Not testable Spaghetti Code Callback Hell Non-DRY Code Smells Application Architecture Rails JS ... and there are code smells all over the place. If you have an ounce of software craftsmanship in you, this should make you cringe.
Postgres MongoDB Rails JS MV* Application Architecture We’re in need of a new approach... Let's try a javascript MVC framework and see how it cleans things up.
Postgres MongoDB Backbone.js AngularJS Application Architecture Rails JS MV* Instead of binding events directly to the DOM, I bind to actions using Backbone/Angular,
Postgres MongoDB Backbone.js AngularJS Backbone.Sync Angular.HTTP Angular.Resource Restful API Application Architecture Rails JS MV* To hit the same restful API,
Postgres MongoDB Handlebars Backbone.js AngularJS Backbone.Sync Angular.HTTP Angular.Resource Restful API Application Architecture Rails JS MV* And allow the framework to update my handlebars templates automatically using bindings. This is very cool! Instead of constantly worrying about whether we need to update the view, we write declarative templates so that no matter what state we're in, the template can handle it.
This is a handlebars template that displays a list of books. Let’s say we start out without any books--it’ll show “No results.” When I add a book, it automatically removes “No results.” and adds the book’s title to the list.
Postgres MongoDB Handlebars Backbone.js AngularJS Backbone.Sync Angular.HTTP Angular.Resource Restful API Application Architecture Rails JS MV* So having declarative templates with data binding is a game-changer.
Postgres MongoDB Handlebars Backbone.js AngularJS Backbone.Sync Angular.HTTP Angular.Resource Restful API Application Architecture Rails JS MV* But there’s one thing that can still require a lot of customization--the Model layer. Backbone.Sync and Angular HTTP & Resource are great, but they’re minimalistic, for example Backbone.Sync is only 50 lines of code. The reason they’re minimalistic is out of necessity-- JSON APIs aren’t standardized, so they have to handle everything, which means they require a lot of configuration to handle most use cases. And that violates one of the core principles of Rails--convention over configuration.
Postgres MongoDB Handlebars Ember.js Ember Data Restful API Rails Ember Application Architecture I’ve found that this combination suits me extremely well. It allows me to write the bare minimum of glue code so that I can quickly start building my application. Here are some areas where Ember really shines...
attr_accessible :title, :body end Declare your models similarly to ActiveRecord post.rb @App.Post = DS.Model.extend author: DS.belongsTo('App.Author') comments: DS.hasMany('App.Comment') tags: DS.hasMany('App.Tag') title: DS.attr('string') body: DS.attr('string') post.coffee Ember Awesomeness On the left we have an ActiveRecord model, on the right an Ember Data model (in coffeescript). DS is Ember Data’s namespace. It’s easy to define associations and get cascading saves for free.
= DS.Model.extend author: DS.belongsTo('App.Author') comments: DS.hasMany('App.Comment') tags: DS.hasMany('App.Tag') title: DS.attr('string') body: DS.attr('string') post.coffee Ember Awesomeness Another easy win is the ability to sideload related records to reduce the number of HTTP requests that your application makes. This is especially great for mobile since latency over 3g is so high. On a recent project we wanted the user experience to be really snappy after the first load, so we basically sideloaded the user’s entire tree of data into a single request. Once the initial HTTP request finished we never had to hit the server again for read operations.
= DS.Model.extend author: DS.belongsTo('App.Author') comments: DS.hasMany('App.Comment', { embedded: true }) tags: DS.hasMany('App.Tag', { embedded: true }) title: DS.attr('string') body: DS.attr('string') post.coffee Ember Awesomeness Another easy win is the ability to sideload related records to reduce the number of HTTP requests that your application makes. This is especially great for mobile since latency over 3g is so high. On a recent project we wanted the user experience to be really snappy after the first load, so we basically sideloaded the user’s entire tree of data into a single request. Once the initial HTTP request finished we never had to hit the server again for read operations.
jQuery) • No need to learn a new mental model • Unified stack • Designed to work out-of-the-box with ActiveModel::Serializers Ember Awesomeness Ember shares Rails’ core philosophy of convention over configuration. It can sometimes be magic-y, for instance if a particular controller doesn’t exist, Ember will create an empty one for you! This is why naming conventions are very important (as in Rails). The heavy reliance on convention is due to the fact that the core team is lead by Yehuda Katz, who was a core maintainer on both Rails and jQuery. I like knowing that the team writing my framework understand my server-side framework extremely well, and were part of building the most popular javascript library out there. Since there’s a shared ecosystem there I feel like I didn’t have to learn a new mental model, and I feel like my stack is well-unified. But one of the greatest things about Ember/Ember Data is that it was designed to work out- of-the-box with ActiveModel::Serializers...
is an outstanding gem that helps you build consistent APIs in Rails. The idea is that the serialization structure should be declarative and independent of the serialized format. A serializer can be used to produce equivalent JSON and XML representations of a given model. Here’s how it works...
format.json { render json: @post } end end posts_controller.rb class PostSerializer < ActiveModel::Serializer attributes :id, :title, :body has_many :comments, :embed => :ids, :include => true has_many :tags, :embed => :ids, :include => true end post_serializer.rb ActiveModel::Serializers You’re probably familiar with the top snippet, it’s from a controller serving up a “show” action for blog posts. Below, we tell ActiveModel::Serializers that we want the serialization of a Post to include id, title, and body attributes, plus embedded comments and tags. Notice I left out created_at and updated_at--this causes those attributes to be left out of the serialization. By the way, you can also add calculated attributes that exist only in the serializer--they help you clean up your API to make it extremely developer-friendly. [pause] Here’s the resulting JSON...
"Hello world!", comment_ids: [ 1 ], tag_ids: [ 1, 2 ] }], comments: [ { id: 1, body: "Test comment" } ], tags: [ { id: 1, name: 'Ponies' }, { id: 2, name: 'Unicorns' } ] } GET /posts/1.json ActiveModel::Serializers ActiveModel::Serializers The great thing about ActiveModel::Serializers is they’re totally nest-able. If I wanted to change the attributes I include for comments, I just make my changes to the CommentSerializer and it will be automatically updated anywhere where a comment is nested. That’s where the power of ActiveModel::Serializers lies in creating a consistent API.
handlebars templates https://github.com/emberjs/ember-rails ActiveModel::Serializers Ember-Rails Gem One other nicety that you’ll want when building Ember apps with Rails is the ember-rails gem. It adds rails generators for installing ember and creating templates and such. And it allows you to separate your handlebars templates into individual files, e.g. posts/ show.handlebars. Then the handlebars templates get compiled down to javascript using the Rails Asset Pipeline as usual.
to learn Ember.js Javascript frameworks can be tough to pick up at first--the stateful MVC model in particular can be challenging to web developers who have only built stateless apps before. Ember has gotten its share of flack for being slow to build great getting-started resources. There are a couple great resources that are relatively new that I’d point you to if you’re interested in learning more about Ember: First, there’s a great screencast from Peepcode that walks you through building a Restaurant Menu app. It was written side-by-side with Yehuda and Tom Dale (Ember’s other main maintainer), so it’s got a lot of practical advice about the _best_ way to use Ember.
(parts 1 & 2, $9/mo) http://railscasts.com/episodes/408-ember-part-1 http://railscasts.com/episodes/410-ember-part-2 How to learn Ember.js Also Ryan Bates has created a 2-part series of Railscasts about Ember that you should check out. The most important thing about learning Ember is...
(parts 1 & 2, $9/mo) http://railscasts.com/episodes/408-ember-part-1 http://railscasts.com/episodes/410-ember-part-2 ActiveModel::Serializers How to learn Ember.js Pay to learn unless your time is worthless! That you should pay for these resources unless your time is worthless. I’d bet that’s not the case for anybody in this room, so it’s worth $12 not to bang your head against a wall.
(parts 1 & 2, $9/mo) http://railscasts.com/episodes/408-ember-part-1 http://railscasts.com/episodes/410-ember-part-2 3. Ember guides, api docs, stack overflow Pay to learn unless your time is worthless! ActiveModel::Serializers How to learn Ember.js Once you’ve been through these resources, feel free to dig into the API and Ember’s guides, and as always, StackOverflow is your friend.s
• Need help on a project? we build web apps using Rails and JS MV* frameworks ActiveModel::Serializers Shout-outs A couple shout-outs... If you’re interested in working with Ember, I know of a couple companies in town who are hiring full-time specifically for Ember. And if you’re a freelancer, we’re always looking for great folks to join us for a project. Additionally, if you’re looking to build out an app in Rails and/or a javascript framework, we’d love to talk to you about how we can help make that happen.
Videos from Ember Camp 2013 http://lanyrd.com/2013/ember-camp/ • Ember.js Google Chrome Extension https://github.com/rapheld/ember_inspector ActiveModel::Serializers Additional Resources
(nice if you’re writing Coffeescript) • Karma (Testacular) uses conf to load dependencies, multi-browser! • Both can be run via CLI (including continuous integration) ActiveModel::Serializers Testing