Monday, 25 August 2014

Intro to ember.js

Ember CLI

Ember is an opinionated JavaScript framework, it subscribes to the Rails philosophy of convention over configuration and makes it very easy to start building well structured, rich, client side applications.
Ember cli is a tool used to help build Ember applications, and similarly has a strong opinion on how you should structure and work with your code. Today's blog post is going to be using both of these tools.
As a Rails developer, the urge to utilise the ember-rails gem is pretty high, however I'm of the opinion that you should keep your Ember application separate from your Rails app and Ember cli provides too good a tool to ignore.
Ember cli is a command line tool thats based on the Ember App Kit project, it is meant to function as a replacement to Ember App Kit. It gives us a great project structure out of the box (not unlike when you generate a new Rails project with rails new), and a few handy generators.
To get started, please follow the instructions at ember cli, and come back when you're ready to proceed.
We're going to be making a simple budgeting application, we'll take incoming transactions, assign them a name, a date, and a price, and assign them to a category.
To start simply run ember new transactions this will create a new transactions folder and generate the application structure. Already we can run ember server from within our application and navigate to our ember app.
To help us identify what's going on in our application, we're going to navigate to ourapp.js file and add the following:
var App = Ember.Application.extend({
  ...
  LOG_TRANSITIONS: true,
  LOG_TRANSITIONS_INTERNAL: true
});

This will assist us in getting a better understanding of what's going on under the hood.

The Router

Next we're going to start setting up some of our routes within app/router.js. The Router in Ember, as opposed to individual route objects, is much like a router in Rails. The main point of difference between a router in Rails and a router in Ember is that a route in Ember represents any one of the possible states of your application, which in turn provides a url.
To start we're going to add our first real route, which will display an index of transactions:
Router.map(function() {
  this.resource('transactions', { path: '/' });
});

Note the addition of the path option, this tells Ember to render the transactions template when visiting the root path of your application.
When you give it a route like the above, it tells Ember that it needs an IndexRoute, aTransactionsRoute and a TransactionsIndexRoute as well as controllers and templates following the same naming convention eg TransactionsIndexController andtransactions/index.
What Ember will do for you is generate those required routes, controllers and templates for you, so you can continue to develop your application until you need to override the default behaviour within those files.

The Model

All this routing needs a model to back it. Once again there's some similarities with Rails here so go ahead and create a model in app/models/transaction.js:
import DS from 'ember-data';

var Transaction = DS.Model.extend({
  name: DS.attr('string'),
  amount: DS.attr('number'),
  occurredOn: DS.attr('date')
});

Transaction.reopenClass({
  FIXTURES: [
  {
    id: 1,
      name: "GYG Burritos",
      amount: "1200",
      occurredOn: "12/04/2014" 
  }
]});

export default Transaction;

We've imported Ember Data, using the import statement at the top of the page. Ember cli provides us the mechanism for this as it uses ES6 modules. How this happens is a bit beyond the scope of this post, however ES6 modules are not fully supported yet, so Ember uses some crafty magic to make these available to use across the board.
In addition we have also defined our model, given it some attributes with different types and created an initial fixture for us to work with. To utilise fixtures, open upapp/adapters/application.js and add the following:
import DS from 'ember-data';
export default DS.FixtureAdapter.extend();

This says to Ember to utilise fixtures as our data source.

A Route

Now we want to make sure when we visit the index of our application we see our list of transactions. To accomplish this, we need to use a route. A route helps define what model should be available to your template when we view our transactions, this is achieved with the model hook in the route.
For our first route, we're going to create the TransactionsRoute inapp/routes/transactions.js
import Ember from 'ember';
var TransactionsRoute = Ember.Route.extend({
  model: function(){
    return this.store.find('transaction');
  }
});

export default TransactionsRoute;

Note the import of Ember, this is another Ember cli requirement that whenever we need ember-data or Ember in our files, we import either of those depending on our needs.
We also return our available transactions in our model hook

A template

We've setup our routes, our model and some initial data, now we need to display our transactions. So we will setup a transactions template in app/templates/transactions.hbs
<ul>
  {{#each}}
    <li>{{name}} {{amount}} {{occurredOn}}</li>
  {{/each}}
</ul>

The each here loops through an array of records, and although we only have one transaction to return, this will ensure our data is displayed correctly and will support additional records when we progress to adding them.
Now if we run ember server from our terminal we should see our fixture data displayed for us.
I should take a step back here and explain that even though ember knows to go and find the transactions template, it's the {{outlet}} statement in app/templates/application.hbs which enables the template to bubble up to be displayed.
We'll be utilizing this concept further when we add additional features, but for now our list of transactions can remain in our transactions template.
We'll continue on from here in the next blog post, but for now if you'd like to take a look at the source code, you can find it on github

A Note on Controllers

We didn't look too closely at Ember Controllers in this post, this will come up in the next post in the series, however ember has created all the controllers we have needed and so far we haven't had to extend their base functionality from what we already have.

Monday, 4 August 2014

Using Models in Migrations

In the primate social experiment of monkeys and bananas (best link I could find), I would be one of the monkeys who got hosed.

When told not to use models in migrations, I went ahead and did so, not understanding why, and got hosed. We can learn from our mistakes not to do something again, but learning why is even more powerful. And learning why we we shouldn’t use models in migrations also teaches us how to use models in migrations safely.

An Example

Firstly, let’s consider an example where we might want to use a model in a migration: Suppose we have a Task model and we have a boolean flag for “is_active” that can only represent two states and we want to migrate this to a new column “status” that might have values “inactive”, “active”, and “pending”. After writing a migration to add a status column, we might write another migration like this:

class UpdateTaskStatus < ActiveRecord::Migration
  def up
    Task.where(:is_active => false).update_all(:status => "inactive")
    Task.where(:is_active => true).update_all(:status => "active")
  end

  def down
    # no action required
  end
end

bin/rake db:migrate and our status fields are populated.

So what can go wrong?

Lots. One of the easiest examples to recognise is when the Task model is refactored. For example, it might be renamed to Job. The next developer who joins the team, or resets their database runs a migration referring to the model Task, which no longer exists.

Other more subtle conflicts can arise when behaviour added to the model class depends on later migrations. For example, adding the paranoia gem to a project and adding the archived_at column to a model will break migrations that previously refer to the model before that column was added to the database.

Changing default scopes, validations and relationships can all have implications in a migration that may be executing in a state when the schema did not have the fields necessary for these changes to function.

There is another caveat: When a model is loaded, it inspects the database to discover which columns exist for that model. If multiple migrations refer to the same model, the model class and column information will be loaded by the first migration using that model. Later migrations using the same model may be missing columns that were added by other migrations. (Yes, you can reset the column information on a model as a workaround).

So is there a way to use a model in the migration safely?

Yes.

Create a new model in the migration itself. This model will be a minimal implementation of only what is required for the migration to execute. No changes made to the model (including being renamed or deleted) will change the use of this new model that is used only in the migration.

Example 1. Creating a new Task model inside the migration:

References to Task within the migration will be to UpdateTaskStatus::Task and not ::Task. This Task model is contained safely within the migration and free from being broken by other changes to the Task model in the application.

class UpdateTaskStatus < ActiveRecord::Migration
  class Task < ActiveRecord::Base
  end

  def up
    Task.where(:is_active => false).update_all(:status => "inactive")
    Task.where(:is_active => true).update_all(:status => "active")
  end
end

Example 2. Creating a new anonymous model inside the migration:

A new subclass of ActiveRecord::Base is created, without a name, and is pointed to the table of interest. Being completely anonymous, no changes to any models in the application can affect this model.

class UpdateTaskStatus < ActiveRecord::Migration
  def up
    model = Class.new(ActiveRecord::Base)
    model.table_name = "tasks"
    model.where(:is_active => false).update_all(:status => "inactive")
    model.where(:is_active => true).update_all(:status => "active")
  end
end