Open tab from javascript

I’ve been super interested in productivity hacking lately. Part of my “look something up” workflow looks like this:

  1. search google for something
  2. open the first N promising looking links in new tabs
  3. click on the tab who’s favicon finishes spinning first
  4. scan, and if dead end CMD+W

I’ve found that the quicker I can see that a page is a dead end the better. It isn’t all that much work to click on each link individually, but because I do it A LOT when learning something new, I’ve always wanted a shortcut.

@vveleva and I built this awesome chrome extension (Auto Open Links): https://chrome.google.com/webstore/detail/auto-open-links/coiapeoijgdcanenjddgdgcepejabljl

When added to chrome, it allows you to press CTRL+SHIFT+3 to open the first three google search results in new tabs.

This morning while we were exploring options for opening a new tab from javascript we stumbled upon this stackoverflow question. Some answers suggest there is no way to open a tab, other give interesting hacks, eventually we decided to build our own with these considerations:

  1. It would be nice to just use vanilla js.
  2. Only needs to work on google search results page.
  3. Must open in new tab, not new window.

NB: It’s completely possible to open a new tab with the following, but for some reason this doesn’t work on the google search results page from a chrome extension:

window.open("https://status203.me/", "_blank");

From some initial digging we found some documentation somewhere that mentions a way to create new chrome tabs:

chrome.tabs.create({ url: "https://status203.me/" }); // nope!

After testing this out, we found that it would only reliably work from the “New Tab”.

At this point I started to think about how I actually open each link. Is there a way that we could simulate the actions I’m actually taking, but with javascript. Well, as I’m opening each link, I hold down the CMD key and click each link. (In chrome that’s how you open a link in a new tab).

Is there a way to construct a custom mouse event and dispatch that event to the links on the page? There is! Via the MouseEvent api!

By simply constructing an instance of MouseEvent with the options we’re interested in we could find the links and dispatch our custom mouse event to those links. Check out the code:

var event = new MouseEvent('click', {
    'metaKey': true
});
var link = document.querySelector('a#myLink'); 
link.dispatchEvent(event);

If for some reason, `window.open` isn’t working for you, consider constructing a custom MouseEvent! 🙂

Here’s the repo: https://github.com/vveleva/auto_open_links if you want to check out the extension!

Open tab from javascript

Rails edge case solved with middleware

Recently I was working with a friend, @sidho on an interesting problem. Sid built this awesome app for tracking beers. It’s a Rails app that pulls some stuff from a brewery API. He setup a webhook and was receiving updates from the API. Problem was: the data posted to the webhook included the key “action” which was used to denote what type of change was happening. By default, when a request is routed, Rails sets the key “action” to the controller action name and the key “controller” to the name of the controller. I spent a little time searching, and looked at the source for about 20 min before deciding the best solution would be to some how intercept the params, rename the key action to something else and then let Rails do its thing.

Here’s our first ever Rack middleware and it’s only job is to rename an incoming param with the name “action” to “beer_db_action”.

# lib/params_fixer.rb
class ParamsFixer
  def initialize(app)
    @app = app
  end

  def call(env)
    request = Rack::Request.new(env)
    if request.params['action']
      request.update_param('beer_db_action', request.params['action'])
    end
    status, headers, resp = @app.call(env)
    [status, headers, resp]
  end
end

# config/application.rb
config.autoload_paths += Dir["#{config.root}/lib/**/"]
config.middleware.use "ParamsFixer"

Checkout our solution if you’re interested 🙂

I’m hoping to write a pull request for the gem/make a Rails version of the gem.

Rails edge case solved with middleware

Solving Presence in Rails: Pusher vs. Node Service

There you are, sipping a mocha, writing another Rails app. It has users, and you’d love it if those users could interact and have some deep meaningful realtime connection. What do you reach for? Pusher? Generally that’s my first go to for realtime stuff! Pusher is awesome. It’s a software as a service platform for adding realtime awesomeness to your
app. As you would expect there are libraries in every flavor so you can use Pusher from whatever crazy setup you’ve got.

In the past, I’ve dropped the pusher gem into Rails apps and Wham! now I’m pushin realtime updates to my users from the server. If you’re curious how easy it is to get started with Pusher + Rails this is it:

If you want to follow along at home, you can checkout the 736e3b861705
branch of github.com/w1zeman1p/code_racer.

Add the `pusher_rails` gem to the Gemfile, then copy and paste the initializer code they give you when you create an app on their site.

# Gemfile
gem 'pusher_rails'

# config/initializers/pusher.rb
require 'pusher'
Pusher.url = "http://#{ some key they give you }@api.pusherapp.com/apps/#{ some app id they give you }"
Pusher.logger = Rails.logger

Initialize an instance of a `Pusher` object in javascript somewhere.
(This is also how you might setup logging).

// app/assets/javascripts/application.js
Pusher.log = function (message) {
  if (window.console && window.console.log) {
    window.console.log(message);
  }
};
var pusher = new Pusher(some key they give you);

That’s it. You’re now up and running and can subscribe to events that are being pushed to the client.

Wow, that was easy. Whats the catch? Where does it fall down? Great question! (Disclaimer: You can get more out of Pusher if you pay $$, I’m interested in squeezing as much out of the free service as possible). This is great if the client is just listening for updates, but as soon as you need clients to emit events to each other, or emit events back to the server, Pusher wants you to pay. (Thanks @Phil Leggetter! The only limitation on free account is number of connections.) I completely understand, seems like a valid business model. That said, it’s surprisingly easy to get more realtime mileage if you extract that logic into a service.

Extract into a service you say…

To checkout the Node service that I extracted take a gander at:
https://github.com/w1zeman1p/code_racer_rt (the juicy stuff is in
lib/rooms.js)

Node.js is a great platform for and has many tools surrounding realtime communication [see socket.io and peer.js]. IMO, it’s got a beautiful evented architecture and great tools for managing tiny requests and streams efficiently.

Following the docs on socket.io was a great start to getting things running locally. Moving the client side logic to the javascript served from my Rails app and replacing all the client side references to localhost to with my heroku domain running the node app was enough to get going.

So what to change in Rails? I was able to strip out every single reference to Pusher, including the gem and initializer :). And then add a few lines requiring the socket.io-client library.

For me, the trick to getting everything to play nicely was setting up the socket.io connection from the client, then as soon as the first Rails page loaded, emitting a `register` event storing a hash of users by socket id in node. Essentially syncing the sessions.

One beauty of using socket.io is that you get presence (who’s online) just by storing this hash of users.

How did I arrive at this solution? Why move away from pusher and into Node? What was the smell/thing to look for that pushed me to make this huge change? Another great question! My presence implementation started to feel, um, hella hacky. Lets look at some code:

At some point I decided that users should be able to see who else is online (presence). I thought of a few ways to accomplish this, the first of which was to emit a `hello` event to all other people in the channel when the page loads. (I think you can do this with paid Pusher, I’m essentially building a toy, so that wasn’t an option).

Okay, option 2: I’ll send an xhr request when the page loads and post to a Rails endpoint (I called it /api/online_users). This was a pretty cool, but fragile solution. Here’s a couple commits with most of the code: w1zeman1p/code_racer/commit/f5e6abee69
w1zeman1p/code_racer/commit/c84e731e0423

The gist is that on document ready, send a POST, on before unload send a DELETE. Then have all clients bind to a channel called `presence` and when an OnlineUser resource is created, trigger that event and notify all users.

// on document ready
$.ajax({
  url: '/api/online_user',
  type: 'POST',
  data: window.CURRENT_RACER
});

// cleanup stuff
function cleanup() {
  CodeRacer.pusher.disconnect();
  $.ajax({
    url: '/api/online_user',
    type: 'DELETE',
  });
}
$(window).on('beforeunload', function () {
  var x = cleanup();
  return x;
});

// bind all users to presence channel, and listen for add_user
CodeRacer.pusher = new Pusher(key);
CodeRacer.presence = CodeRacer.pusher.subscribe('presence');
CodeRacer.presence.bind('add_user', function (data) {
  console.log('User coming online:', data);
});

From the Rails side, one option is to store all these users that are online in the SQL database. I didn’t go down that path for fear that talking to the SQL db would be too slow (I didn’t do any perf testing here, might be worth a try).

I tried using the Rails cache, in production I used memcachier. This worked pretty well, until some users `beforeunload` DELETE never fired and they ended up sticking around. More code?

# app/controllers/api/online_users_controller.rb
before_action :get_users
after_action :set_users

def create
  @users << user_hash unless @users.include?(user_hash)
  Pusher['presence'].trigger('add_user', user_hash)
  render json: @users
end

def user_hash
  {
    id: current_user.id,
    nickname: current_user.nickname
  }
end

def get_users
  @users ||= Rails.cache.read('users') || Set.new
end

def set_users
  Rails.cache.write('users', @users.to_a)
end
# ...

Kinda hacky? Yeah, I thought so too. It all depends on the `beforeunload` event firing just right and actually completing the DELETE request perfectly to remove the user from the cache. I suppose I could poll… ew. gross. No thanks.

Option 3! Replace the online user resource completely with a node service. This was the winner. No Rails controller (talk about skinny ;)), No Rails cache, No $.ajax requests, all socket.io.

Here’s a jumpstart for getting some node code running socket.io and doing presence with `register` and `online_users` events. The idea here is that we’ll emit a `register` event from the client when the page loads, and we’ll listen for an `online_users` event for batch updates about who’s online (this could probably be more efficient if we just listened for add and remove rather than batch updating?).

// Node application running in a seprate instance than the Rails server.
// app.js
var http = require('http'),
  static = require('node-static'),
  file = new static.Server('./public'),
  _ = require('lodash');

var server = http.createServer(function (req, res) {
  req.addListener('end', function () {
    file.serve(req, res);
  }).resume();
});

// process.env.PORT is for heroku 🙂
server.listen(process.env.PORT || 8000);
var io = require('socket.io')(server);
var users = {};

io.on('connection', function (socket) {
  socket.on('register', function (data) {
    users[socket.id] = data;
    io.sockets.emit('online_users', _.values(users));
  });

  socket.on('disconnect', function () {
    delete users[socket.id];
    io.sockets.emit('online_users', _.values(users));
  });
});

Now that we’ve fired up a node app and we’re listening for connections, lets see the code we’ll need from the client.

// app/assets/javascripts/application.js
var socket = io('http://mynodeapp.herokuapp.com');
socket.on('online_users', function (data) {
  console.log('online users: ', data);
});
// on document ready
socket.emit('register', window.CURRENT_RACER);

Where can we go from here? What incredible powers does this give us? Peer to peer! A feature I’d love to add is voice/video of the racers, see that look of focus and determination…

as the type as fast as possible :). Seems like a pretty reasonable feature to add with peer.js using Web RTC.

Solving Presence in Rails: Pusher vs. Node Service

Backbone rule learned during a JavaScript Refactoring

One of my goals for 2015 is to up my typing speed. I’ve never been that great a typer and I’m currently averaging about 75 WPM and shooting for 100 WPM by the end of the year. As part of my goal I’ve been practicing with some really great web based type tutors, games and tools. If you’re interested in playing some online typing games for free, you should definitely checkout typeracer and ztype.

In the interest of building a tool and forwarding my goal I’ve created WPM Challenge. It’s a typing challenge similar to typeracer. I learned a couple interesting things while building this little application that I’m excited to share with you.

Some background: This project is built using Rails and Backbone. The real time stuff uses Pusher and the auth is mostly omniauth gems and some stuff in the User model.

This will be a story about some javascript refactoring. If you’d like to see the before and after check these commits out.

track.js before
track.js after

My first stab at this problem used a Track backbone model, which represented the content being typed. This quickly attracted many other functions and ended up being a junk drawer of functionality, handling, joining new cars to the track, as well as about a dozen method that were delegated to an instance of WordChecker, who’s responsibility it is to manage current state of the typer as they advance through the content. At first I didn’t write any tests, in fact this wasn’t intended to be a real time collaborative typing challenge at all. At some point I decided it would be cool to race my friends and keep track of WPM for each track.

I admittedly wrote zero javascript tests at the beginning and was quite fearful of making this big refactoring. In a later post I’ll talk about how I used the teaspoon gem to get up and running writing tests for javascript pretty quickly in Rails, but for now, know that I just started adding javascript tests at the start of this refactoring.

The Problem

The problem was that the TrackDetail view and the Track model were taking on way too much responsibility. These problems manifested themselves in two ways. 1) I found this super odd code smell where the Track model was delegating more than half of its methods down to a WordChecker. I think the goal here was to keep the word checking logic abstracted away from the view as much as possible, but in the end the view was calling a handful of wordChecker methods just on the Track. IMO pretty shitty.

Smell 1: feature envy

// app/assets/javascripts/models/track.js
CodeRacer.Models.Track = Backbone.Model.extend({
  // ...
  currentWordCount: function () {
    return this.wordChecker().currentWordCount();
  },

  checkWord: function (word) {
    return this.wordChecker().checkWord(word);
  },

  checkLetter: function (letter) {
    return this.wordChecker().checkLetter(letter);
  },

  wordComplete: function (word) {
    return this.wordChecker().wordComplete(word);
  },

  backSpace: function () {
    return this.wordChecker().backSpace();
  },

  content: function () {
    return this.wordChecker().render();
  },

  moreWords: function () {
    return this.wordChecker().moreWords();
  },

  wordCount: function () {
    return this.wordChecker().wordCount();
  },

  percentComplete: function () {
    return this.wordChecker().percentComplete();
  },
  //...

Smell 2: Too Much Setup in View#initialize

2) The TrackDetail initialize method also became super gross. It was initializing a ton of objects and doing a lot of setup for the race. Check it out:

CodeRacer.Views.TrackDetail = Backbone.View.extend({
  initialize: function () {
    this.listenTo(this.model, 'sync', this.render);
    this.timer = new CodeRacer.Models.Timer();
    this.model.join(this.timer); // joins the race as the current user and sets up pusher channel
    this.carsIndex = new CodeRacer.Views.CarsIndex({
      collection: this.model.cars()
    });
    this.timerView = new CodeRacer.Views.TrackTimer({
      timer: this.timer,
      track: this.model
    });
    this.listenTo(this.timer, 'go', this.startRace);

    this.leaderBoardView = new CodeRacer.Views.LeaderBoard({
      collection: this.model.leaders()
    });
  },
  // ...

Something better

In my Rails controllers, I’ve been trying to follow the rules laid out by Sandi Metz in a Ruby Rogues episode a few months back. When attempting to keep methods short and keep only one instance variable per controller I’ve noticed that my views and controller actions are simpler, but more interestingly a lot of the logic is pushed into new ruby objects that do not fall into the Rails architecture. Some people call these service objects, call them what you want to, they’re just objects. My new found confidence in creating objects outside of the framework has led me to create two new classes in this project that do not live directly in the Backbone architecture, but provide great encapsulation of my data an business logic.

The rule I’ve discovered during this extraction: Only refer to one model or collection in a backbone view. I extracted logic from the TrackDetail view and from the Track model and put them in a class called Race. The Race class expects a track, timer, and a wordChecker and is the one thing that the view refers to. It handles working with the word checker and forwards/delegates events raised from the Track or from the Timer object. Check it out:

New Race class. Notice the dependency injection, made this especially testable 🙂

CodeRacer.Models.Race = function (track, timer, wordChecker) {
  this.track = track;
  this.timer = timer;
  this.wordChecker = wordChecker;
  this._valid = true;

  this.listenTo(track, 'change:content', function () {
    this.wordChecker.setContent(track.get('content'));
  });
  this.forwardEvents();

  track.fetch();
  track.join(timer);
};

CodeRacer.Models.Race.prototype = {
  forwardEvents: function () {
    this.listenTo(this.track, 'sync', function () {
      this.trigger('sync');
    });

    this.listenTo(this.timer, 'go', function () {
      this.trigger('go');
    });

    this.listenTo(this.wordChecker, 'over', function () {
      this.over();
    });

    this.listenTo(this.wordChecker, 'next', function () {
      this.next();
    });
  },

  over: function () {
    this.track.notify(this.wpm(), this.wordChecker.percentComplete(), true);
    this.timer.stop();
    this.trigger('over');
  },

  cars: function () {
    return this.track.cars();
  },

  leaders: function () {
    return this.track.leaders();
  },

  content: function () {
    return this.wordChecker.render();
  },

  checkWord: function (word) {
    this._valid = this.wordChecker.checkWord(word);
    return this._valid;
  },

  valid: function () {
    return this._valid;
  },

  wpm: function () {
    if (this.started() && this.timer.seconds > 1) {
      return (this.wordChecker.currentWordCount() / (this.timer.seconds / 60)).toFixed(2);
    }
    return 0;
  },

  next: function () {
    this.track.notify(this.wpm(), this.wordChecker.percentComplete());
    this.trigger('next');
  },
};

_.extend(CodeRacer.Models.Race.prototype, Backbone.Events);

TrackDetail refactored to use only one thing.

// app/assets/javascripts/views/track_detail.js
CodeRacer.Views.TrackDetail = Backbone.View.extend({
  initialize: function (options) {
    this.race = options.race;
    this.listenTo(this.race, 'sync', this.render);
    this.listenTo(this.race, 'go', this.startRace);
    this.listenTo(this.race, 'next', this.advanceWord);
    this.listenTo(this.race, 'over', this.gameOver);
    this.initializeSubviews();
  },

  advanceWord: function () {
    this.renderContent();
    this.clearInput();
  },

  initializeSubviews: function () {
    this.carsIndex = new CodeRacer.Views.CarsIndex({
      collection: this.race.cars()
    });

    this.timerView = new CodeRacer.Views.TrackTimer({
      race: this.race,
      timer: this.race.timer, // probably not necessary anymore
      track: this.model // probably not necessary anymore
    });

    this.leaderBoardView = new CodeRacer.Views.LeaderBoard({
      collection: this.race.leaders()
    });
  },
  // ...

I think the end result is much cleaner, and now that I’ve got some test coverage on WordChecker and Race, I’m much more confident in making changes. Also, moving forward and adding features, subViews to the TrackDetail view will be a breeze.

Backbone rule learned during a JavaScript Refactoring

App Landing Page for Ionic app

We’ve all been to sites that explain features of an app and entice you to visit the market place and download. If you’ve developed an app and are starting to build out a landing page, you might have googled “app landing page” and found some themes from themeforest.net. These are flashy designs that display the features of the app and expect the creator to drop in app screenshots that my slide around or transition as you move between features.

Something great about apps built with ionic framework is that you can demo the nearly full (minus device features) app right on your marketing page (not sure this is cool, legally). I’ve done that for a couple ionic apps: Pushbit and Insider AI and want to show you how.

These two pages are both being served from Rails apps, but you shouldn’t have any difficulty getting things working from your own server.

The key here is to run the ionic app in an iframe.

In Rails, there is a /public directory that contains static html. In /public I’ll create a directory called app and copy the contents of www to app.

In the html for the page, I’ll put the image of the device as the background, then an iframe pointing to the app’s index.html. The iframe should be in an iframe tag, but to comply with the blog formatting I’ve omitted the tag brackets.

<div id="phone">
  <img src="/assets/iphone6.png">
  iframe src="/app/index.html" frameBorder="0" class="screens" /iframe
</div>
App Landing Page for Ionic app

Lets do this!

Every place I’ve ever lived has had a different pace. I spent my childhood in a small mountain town in Tahoe called Kings Beach. KB has a super chill, very laid back pace. Everyone is either a tourist or in love with the mountains and lake. I would say, the area provides a nice lifestyle, especially for those interested in the out doors and relaxing.

Just before starting high school we moved to Reno, NV. Close by, but much more reasonable cost of living. The pace in Reno is definitely more upbeat than KB. More people, more hustle. There’s some budding tech but most dev jobs are for defense or gaming.

In 2012 I moved my family to San Francisco to accelerate my career, meet people and enjoy the scene as a techie. SF is MUCH faster paced than any where I’ve experienced. People pile onto MUNI and Bart heading to work or meetups. It seems that everyone wants to start a company, and everyone definitely drinks coffee like they’ve co-founded 3. The cost of living in the bay is so high, it’s hustle or move.

Many people like me have recently moved to the bay for tech in some way or another. It feels like ‘the homeland’ of tech. Some complain about gentrification, which I don’t really have an opinion about. It is exciting to think that the iPhone I’m composing this post on, the iOS, the app and keyboard, the fitbit on my wrist, we’re all created by BUILDERS, Engineers, Devs, Designers just a few miles from me. That feeling is super motivating and empowering.

Today is the day. A friend of mine just told me a story: Running across the Golden Gate Bridge. On one of the pillars is a placard with the names of the engineers who contributed to the construction. Those men and women have their name in history. At the time they were masters of their craft, in a place and time where the Golden Gate Bridge was necessary and they did it. Today is the day for US engineers to put our name in the record books. Today is the day to build incredible things that will help billions of people.

The impact we can make is profound and lasting. Go out and change the world! One line of code at a time 🙂

ggbridge

Lets do this!

ES6 Model layer for Angular.js

Many of the so called MV* frameworks have some explicit support for a model layer. When working in backbone.js, the model layer is very clearly defined in Backbone.Model and Backbone.Collection.

Instances of Backbone.Model and Backbone.Collection interact with a rest api using $.ajax. In the world of backbone there is a lot of buy in to the evented architecture. When a model or collection finishes fetching, the instance publishes an event which listeners can then act on. They have clear #save, #create, #fetch methods that hit the server and update the model accordingly.

Since working with angular I’ve explored a few solutions (Restangular and $resource) for managing the model layer, but was left wanting. I feel like the designers of angular wanted to be a bit more flexible at the model layer and as a result didn’t build in much on top of plain-old-javascript-objects (POJO).

As a result Angular has a component called Service which when injected into a function new’s up an instance of the Service object which might contain your custom logic for interacting with a backend API or with local storage.

I found myself repeating a lot of logic for each service and essentially rewriting much of the Backbone.Model class in my angular services. For example:

myApp.factory('Workouts', function ($http, $q, loc) {
    function url(id) {
      if (id) {
        return loc.apiBase + '/workouts/' + id;
      }
      return loc.apiBase + '/workouts';
    }

    function Workout(attrs) {
      this.id = attrs.id;
      this.completed_date = attrs.completed_date;
      this.workout_sets = attrs.workout_sets;
    }

    return {
      all: function () {
        var dfd = $q.defer();
        $http.get(url()).then(function (resp) {
          var workouts = _.map(resp.data, function (w) {
            return new Workout(w);
          });
          dfd.resolve(workouts);
        }, function (resp, status) {
          $rootScope.$broadcast('event:auth-loginRequired', status);
          dfd.reject(resp.data);
        });
        return dfd.promise;
      },
      get: function (id) {
        var dfd = $q.defer();
        $http.get(url(id)).then(function (resp) {
          dfd.resolve(resp.data);
        }, function (resp) {
          dfd.reject(resp.data);
        });
        return dfd.promise;
      }
    };
  });

The all method here was essentially the same across all services in the system and only differed slightly in cases where I was massaging the incoming data.

@shawndromat pointed me towards a pattern where using a Model factory might help by returning a constructor function that I could use for each of my Model layer classes.

Here’s a simplified (without caching) version of my Model factory:

  myApp.factory('Model', function ($http, $q, $window, loc) {
    return function (options) {
      var path = options.path;
      var url = loc.apiBase + path;

      class Model {
        constructor(attrs) {
          this.setup.apply(this, arguments);
          attrs = attrs || {};
          this.attributes = {};
          this.set(this.parse(attrs));
          this.initialize.apply(this, arguments);
        }

        get id() {
          return this.attributes.id;
        }

        initialize() {
        }

        setup() {
        }

        set(attrs) {
          for(var attr in attrs) {
            this.attributes[attr] = attrs[attr];
          }
          return this;
        }

        get(key) {
          return this.attributes[key];
        }

        parse(response) {
          return response;
        }

        save() {
          if(this.id) {
            return this.update();
          } else {
            return this.create();
          }
        }

        update() {
          var dfd = $q.defer();
          $http
            .put(this.url(), this.attributes)
            .then((response) => {
              this.set(this.parse(response.data));
              dfd.resolve(this);
            }, (response) => {
              dfd.reject(this);
            });
          return dfd.promise;
        }

        create() {
          var dfd = $q.defer();
          $http
            .post(this.url(), this.attributes)
            .then((response) => {
              this.set(this.parse(response.data));
              dfd.resolve(this);
            }, (response) => {
              dfd.reject(this);
            });
          return dfd.promise;
        }

        url() {
          if(this.id) {
            return url + '/' + this.id;
          } else {
            return url;
          }
        }
      }

      Model.url = () => { return url; };

      var _all = [];

      Model.all = function () {
        $http.get(url, { cache: true }).then((response) => {
          _.each(response.data, (data) => {
            if(!_.any(_all, (m) => {
              return m.id === data.id;
            })) {
              _all.push(new Model(data));
            }
          });
        });

        return _all;
      };

      Model.create = function (attributes) {
        var model = new Model(attributes);
        _all.push(model);
        return model.save();
      };

      return Model;
    };
  });

By injecting the Model class into other factories I can create constructor functions that override extend business logic, as well as extend interactions with the backend.

  myApp.factory('Workout', function (Model, WorkoutSet) {
    var Workout = Model({ path: '/workouts' });

    Workout.prototype.setup = function () {
      this.workout_sets = [];
    };

    Workout.prototype.parse = function (response) {
      if(response.workout_sets) {
        console.log('response has workout_sets');
        this.workout_sets = _.map(response.workout_sets, (s) => {
          return new WorkoutSet(s);
        });
        delete response.workout_sets;
      }
      return response;
    };

    return Workout;
  });

I would love to hear your comments and suggestions regarding this implementation. 🙂

ES6 Model layer for Angular.js