Slide 1

Slide 1 text

Ember.js — Rails client and server frameworks that were made for each other Atlanta Ruby User Group May 8th, 2013

Slide 2

Slide 2 text

Jason Ardell Agile Engineering https://github.com/ardell Introductions

Slide 3

Slide 3 text

Backbone.js AngularJS Ember.js and many more... Javascript MV* Frameworks We’re 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?

Slide 4

Slide 4 text

• Recognizable/intuitive project structure • 2-way data binding • Routing • 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.

Slide 5

Slide 5 text

Libraries Frameworks

Slide 6

Slide 6 text

http://todomvc.com One great way to compare the many javascript frameworks 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.

Slide 7

Slide 7 text

• Instructional & portable • Only views & controllers • 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.

Slide 8

Slide 8 text

Application Architecture db model controller view I’m sure most of 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.

Slide 9

Slide 9 text

Application Architecture db model controller view model controller view Client 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.

Slide 10

Slide 10 text

Views Controllers ORM Data Store ERB HAML Slim ActionController ActiveRecord Postgres MongoDB Rails Application Architecture

Slide 11

Slide 11 text

Views Controllers ORM Data Store ERB HAML Slim ActionController ActiveRecord 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.

Slide 12

Slide 12 text

Views Controllers ORM Data Store ERB HAML Slim ActionController ActiveRecord Postgres MongoDB $.live Application Architecture Rails JS I listen for click events, using jQuery’s live or bind...

Slide 13

Slide 13 text

Views Controllers ORM Data Store ERB HAML Slim ActionController ActiveRecord Postgres MongoDB $.live $.ajax Application Architecture Rails JS use $.ajax

Slide 14

Slide 14 text

Views Controllers ORM Data Store ERB HAML Slim ActionController ActiveRecord Postgres MongoDB $.live $.ajax Restful API Application Architecture Rails JS to hit a restful API

Slide 15

Slide 15 text

Views Controllers ORM Data Store ERB HAML Slim ActionController ActiveRecord 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...

Slide 16

Slide 16 text

Views Controllers ORM Data Store ERB HAML Slim ActionController ActiveRecord Postgres MongoDB $.html $.live $.ajax Restful API Not testable Application Architecture Rails JS It's not testable,

Slide 17

Slide 17 text

Views Controllers ORM Data Store ERB HAML Slim ActionController ActiveRecord Postgres MongoDB $.html $.live $.ajax Restful API Not testable Spaghetti Code Application Architecture Rails JS creates spaghetti code,

Slide 18

Slide 18 text

Views Controllers ORM Data Store ERB HAML Slim ActionController ActiveRecord Postgres MongoDB $.html $.live $.ajax Restful API Not testable Spaghetti Code Callback Hell Application Architecture Rails JS leads to callback hell,

Slide 19

Slide 19 text

Views Controllers ORM Data Store ERB HAML Slim ActionController ActiveRecord 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...

Slide 20

Slide 20 text

Views Controllers ORM Data Store ERB HAML Slim ActionController ActiveRecord 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.

Slide 21

Slide 21 text

Views Controllers ORM Data Store ERB HAML Slim ActionController ActiveRecord 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.

Slide 22

Slide 22 text

Views Controllers ORM Data Store ERB HAML Slim ActionController ActiveRecord 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,

Slide 23

Slide 23 text

Views Controllers ORM Data Store ERB HAML Slim ActionController ActiveRecord Postgres MongoDB Backbone.js AngularJS Backbone.Sync Angular.HTTP Angular.Resource Application Architecture Rails JS MV* Use Backbone.Sync or Angular.HTTP/Resource

Slide 24

Slide 24 text

Views Controllers ORM Data Store ERB HAML Slim ActionController ActiveRecord Postgres MongoDB Backbone.js AngularJS Backbone.Sync Angular.HTTP Angular.Resource Restful API Application Architecture Rails JS MV* To hit the same restful API,

Slide 25

Slide 25 text

Views Controllers ORM Data Store ERB HAML Slim ActionController ActiveRecord 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.

Slide 26

Slide 26 text

    {{#each books}}
  • {{title}}
  • {{else}}
  • No results.
  • {{/each}}
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.

Slide 27

Slide 27 text

Views Controllers ORM Data Store ERB HAML Slim ActionController ActiveRecord 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.

Slide 28

Slide 28 text

Views Controllers ORM Data Store ERB HAML Slim ActionController ActiveRecord 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.

Slide 29

Slide 29 text

Views Controllers ORM Data Store ERB HAML Slim ActionController ActiveRecord 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...

Slide 30

Slide 30 text

class Post < ActiveRecord::Base belongs_to :author has_many :comments has_many :tags 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.

Slide 31

Slide 31 text

Embedded records save HTTP requests (great for mobile btw!) @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 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.

Slide 32

Slide 32 text

Embedded records save HTTP requests (great for mobile btw!) @App.Post = 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.

Slide 33

Slide 33 text

• Convention over configuration • Yehuda and team (Rails & 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...

Slide 34

Slide 34 text

Makes your API consistent & intuitive ActiveModel::Serializers ActiveModel::Serializers https://github.com/rails-api/active_model_serializers 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...

Slide 35

Slide 35 text

ActiveModel::Serializers def show @post = Post.find(params[:id]) respond_to do |format| format.html 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...

Slide 36

Slide 36 text

{ posts: [{ id: 1, title: "Sample Blog Post", body: "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.

Slide 37

Slide 37 text

• Adds Ember generators • Allows you to separate out 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.

Slide 38

Slide 38 text

1. Peepcode Screencast “Fire up Ember” ($12) https://peepcode.com/products/emberjs ActiveModel::Serializers How 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.

Slide 39

Slide 39 text

1. Peepcode Screencast “Fire up Ember” ($12) https://peepcode.com/products/emberjs 2. Railscasts (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...

Slide 40

Slide 40 text

1. Peepcode Screencast “Fire up Ember” ($12) https://peepcode.com/products/emberjs 2. Railscasts (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.

Slide 41

Slide 41 text

1. Peepcode Screencast “Fire up Ember” ($12) https://peepcode.com/products/emberjs 2. Railscasts (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

Slide 42

Slide 42 text

• Want to work with Ember? full-timers & freelancers needed • 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.

Slide 43

Slide 43 text

Jason Ardell https://github.com/ardell [email protected] ActiveModel::Serializers Questions? Any questions?

Slide 44

Slide 44 text

• EmberJS.com, esp: http://emberjs.com/guides/ http://emberjs.com/api/ • StackOverflow: http://stackoverflow.com/questions/tagged/ember.js http://stackoverflow.com/questions/tagged/ember-data • 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

Slide 45

Slide 45 text

• Compiles coffeescript & handlebars • Combines/minifies javascript ActiveModel::Serializers Rails Asset Pipeline

Slide 46

Slide 46 text

• Konacha / Mocha / Chai uses Rails Asset Pipeline (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