Logo

Who is talking?

Archive

Taking Advantage of Blocks not Checking Parameter Count

over 3 years ago | Alex Rothenberg: Alex Rothenberg

As Ruby programmers we don’t write for loops instead we iterate over enumerables. We’ve got a rich library of methods like each, map, select or detect to choose from and they all take a block that lets us do something as each element passes by. It leads to a functional style of programming. As I was talking with Pat Shaughnessy about his recent article Use An Ask, Don’t Tell Policy With Ruby I realized when I chain these methods together sometimes the blocks take different numbers of parameters. For example if we want to find the first 3-letter word in a wordlist we can use the detect method %w(Hi there how are you).detect do |word| word.length == 3 end # => "how" Here’s where it gets a little weird. If we are looking for the index of the first 3-letter word we chain the same detect method after each_with_index. each_with_index yields the element and index and somehow those 2 parameters are passed all the way through to the detect block. %w(Hi there how are you).each_with_index.detect do |word, index| word.length == 3 end # => ["how", 2] That seems strange! How can the detect method block sometimes accept 1 parameter and at other times accept 2? Blocks don’t check their arity It turns out that in Ruby blocks don’t check how many parameters they are passed. Arity is the formal word for “the number of arguments passed to a function”. This means you can pass 3 arguments to a block expecting 1 and the extra ones will be ignored. You can also pass 1 to a block expecting 3 and the extra parameters will be nil. def test yield :a yield :a, :b, :c end test {|x| puts x.inspect} # :a # :a test {|x, y, z| puts [x, y, z].inspect} # [:a, nil, nil] # [:a, :b, :c] Its interesting that we can be so flexible when writing blocks and that got me thinking about two other Ruby concepts closely related to blocks - procs and lambdas. Can we do something similar with them? The same trick with lambdas and procs? Blocks are closures that functions can yield to and there are two other types of clojures you can use programmatically in Ruby lambdas and procs. They are almost the same as each other and both report themselves as instances of the Proc class. They differ in what happens if you return from inside one and whether they enforce arity. Lambdas enforce arity while procs do not. Both lambdas and procs are objects you can assign and pass around while blocks can only be created as syntax when calling a method. First we’ll try our example with a proc and see it continue to work whether we yield 1 or 2 parameters. Proc behave just like a block and we get the same results we did with blocks before. proc = Proc.new {|word, index| word.length == 3 } # => #<Proc:0x007fdae31547d8@(irb):88> %w(Hi there how are you).each_with_index.detect &proc # => ["how", 2] %w(Hi there how are you).detect &proc # => "how" When we try with a lambda we see the difference. Lambdas enforce arity and we get an error when we try to call the lambda expecting 2 parameters with only 1. lambda = ->(word, index) { word.length == 3 } # => #<Proc:0x007fdae302b7d0@(irb):74 (lambda)> %w(Hi there how are you).each_with_index.detect &lambda # ArgumentError: wrong number of arguments (1 for 2) # from (irb):156:in `block in irb_binding' # from (irb):158:in `each' # from (irb):158:in `detect' # from (irb):158 # from /Users/alex/.rvm/rubies/ruby-2.1.1/bin/irb:11:in `<main>' %w(Hi there how are you).detect &lambda # ArgumentError: wrong number of arguments (1 for 2) # from (irb):156:in `block in irb_binding' # from (irb):160:in `each' # from (irb):160:in `each_with_index' # from (irb):160:in `each' # from (irb):160:in `detect' # from (irb):160 # from /Users/alex/.rvm/rubies/ruby-2.1.1/bin/irb:11:in `<main>' This is even more surprising than I expected. I expected the last one to fail as it is only passing 1 parameter to a lambda expecting 2 but why did the .each_with_index.detect &lambda give an error? A bit more testing shows that map works. lambda = ->(word, index) { word.length == 3 } # => #<Proc:0x007fdae302b7d0@(irb):74 (lambda)> %w(Hi there how are you).each_with_index.map &lambda # => [false, false, true, true, true] Is this a bug in MRI? In both JRuby and Rubinius detect and map work the same. I’m not sure but am wondering whether I’ve uncovered a bug in MRI (that would be exciting!) I’ll have to ask my friend Pat Shaughnessy for help spelunking into the MRI source. Putting this aside for a moment we’ll switch to the map version and think about how to overcome the arity checking in lambdas. We can force our code around it by using the splat operator. Instead of defining the lambda with specific arguments we tell it to expect an array of whatever arguments it gets. lambda = ->(*args) { args.first.length == 3 } # => #<Proc:0x007fdae313f270@(irb):85 (lambda)> %w(Hi there how are you).each_with_index.map &lambda # => [false, false, true, true, true] %w(Hi there how are you).map &lambda # => [false, false, true, true, true] Would you ever create a lambda like this? Probably not, but its kinda fun to know you can. This is also the first time I’ve had to think deeply about blocks, procs and lambdas and dig into their differences.

Learning D3.js by Building a Chart

over 3 years ago | Alex Rothenberg: Alex Rothenberg

If you’re doing any JavaScript you’ve probably heard of d3.js. In fact Github Graphs are built with it so even if you weren’t aware, I’m sure you’ve seen it there. But maybe you haven’t been sure how to get started using it yourself. Its not too hard once you have a mental model of how it works. Today we’re going to walk through how to build a bar chart that shows some interesting weather data about Boston as a way to learn more about d3.js. http://alexrothenberg.github.com/examples/d3-chart/index.html Before we get into any details here are a few big picture ideas to keep in mind d3 is all about binding data with DOM elements. d3 has an enormous API covering charts, maps, arrays, and all sorts of other things svg is a great fit when you’re creating charts or other visualizations Binding data to the DOM The first thing to know is that d3 stands for Data-Driven Documents and its core job is to let you synchronize data to DOM elements. Let’s start by seeing how we can use it to add some DOM elements. 1<script src="http://d3js.org/d3.v3.min.js"></script> Once we include the d3.js script in our page, we have a top level d3 object we can use to start adding elements. If you haven’t used SVG (scalable vector graphics) its a series of tags added in HTML5 that let us define shapes on our page. They can be styled with css and manipulated with javascript just like traditional html tags but are designed more for shapes than text so we can do all sorts of interesting drawings with them. 1 2 3 4var svg = d3.select('body').append('svg') .attr('height', '200') .attr('width', '500'); var g = svg.append('g'); This looks kinda like jQuery but with a slightly different syntax and that’s not by accident. Let’s go through it line-by-line Line 1 - We append a new svg element inside the body and return a d3 object representing that element. Line 2-3 - D3 chains everything just like jQuery so we can set height and width attributes on the svg element Line 4 - Add a g (or “group”) element within the svg The page won’t look any different to a user because the svg and g elements don’t have any visual representation, however, if we were to inspect the DOM we’d see our tags in there 1 2 3 4 5<body> <svg height="200" width="500"> <g></g> </svg> </body> We’re started on the document part so time to add the data. Here’s a simple tsv (tab-separated values) file of average snow totals in Boston by month (all the data files are on github if you want to look). Month Average Oct 0.1 Nov 0.6 Dec 12 Jan 14.9 Feb 11.8 Mar 7 Apr 0.3 Now we will use the d3 tsv API for parsing our data and inserting an element for each row into the DOM. Before we look at the code there are two concepts to mention briefly. We’re going to create a bunch of rect elements within our svg. As the name suggests the browser will draw them as rectangles. Also the main mechanism behind d3 is joining data to the DOM. Basically a dataset is joined to a set of DOM elements and d3 ensures that there will be the same number of DOM elements as rows of data. Mike Bostock has explained this really well in thinking with joins. Thinking with joins So what does this look like in code? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 // This is unchanged var svg = d3.select('body').append('svg') .attr('height', '200') .attr('width', '500'); var g = svg.append('g'); var parseRow = function(row) { return { month: row.Month, average: parseFloat(row.Average) } }; d3.tsv('data/snow.tsv', parseRow, function(data) { var rect = g.selectAll('.bar').data(data) .enter().append('rect') rect.attr('class', 'bar') .attr('width', 10) .attr('height', 100) .attr('x', function(d) { return d.month.charCodeAt(0)}) }) Line 14 - Load and parse the snow.tsv file. We give it 2 callbacks, the first for formatting each row and the last to process the data by adding it to our DOM Lines 7-12 - Format each row by converting the average column from a string to a number Line 15 - Bind our data to all the elements with the bar class (it’s an empty set when the page loads but this becomes useful further on) Line 16 - for each data item without a corresponding DOM element (that’s what enter() means) create a rect element Lines 17-20 - set a bunch of positioning attributes on each rect. The attributes can either be a contant or a function that gets called with the data item d3 attached to this particular rect element. Now we have a bar but they’re all on top of each other (mouse over what’s below to see) http://alexrothenberg.github.com/examples/d3-chart/basic-chart.html To space the bars out a bit we can change the logic for the x attribute to .attr('x', function(d) { return d.month.charCodeAt(0) * 5 }) but now it’s weirdly in the middle of the page. http://alexrothenberg.github.com/examples/d3-chart/basic-chart2.html Next we will look at some d3 chart APIs that can help us position the bars instead of spacing based on the first letter of each month. Scaling with the D3 Scale API What we need to do is scale both the x and y dimensions based on the data we have. The width of each bar depends on how many months we are displaying and also the height depends on the height of the month with the most snow. Luckily d3 has us covered with its scales API. We’re going to use an ordinal scale for the months and linear scale for the inches of snow. We change the tsv callback to use these scales when setting the width, height, x & y attributes of each rect. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 d3.tsv('data/snow.tsv', parseRow, function(data) { var months = data.map(function(d) { return d.month }) var x = d3.scale.ordinal() .rangeRoundBands([0, 400], .1) .domain(months) var averages = data.map(function(d) { return d.average }) var y = d3.scale.linear() .range([150, 0]) .domain([0, d3.max(averages)]) var rect = g.selectAll('.bar').data(data).enter().append('rect') rect.attr('class', 'bar') .attr('width', x.rangeBand()) .attr('height', function(d) { return 150 - y(d.average)}) .attr('x', function(d) { return x(d.month) }) .attr('y', function(d) { return y(d.average) }) }) Let’s look in detail at how we are scaling the x dimension. First we do some setup looking at our data as a whole Line 2 - Extract the months from our data Line 3 - Tell d3 our x dimension will have ordinal values (since we can count and sort but not measure the names of the months). Line 4 - We want it to stretch the bars so they go all the way across our svg with some padding between each Line 5 - Apply these calculations to the months in our data. Now set the right x and width on each rectangle. 1. Line 14 - Set each bar to the width based on all the calculations above 2. Line 16 - Use the x to tell us where to place each bar You can see the same logic applied in the y dimension on lines 6-9 then 15 & 17. The only difference is we’re using a linear scale because “average inches of snow” is a number http://alexrothenberg.github.com/examples/d3-chart/scaled.html Now that’s looking much better! But a bar chart should really label its axes … Adding Axis labels You can probably guess that if we need to do axes, there’s a d3 API for axes. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23var g = svg.append('g') .attr("transform", "translate(40, 0)"); g.append('g') .attr('class', 'x axis') .attr('transform', 'translate(0, 150)'); g.append('g') .attr('class', 'y axis'); d3.tsv('data/snow.tsv', parseRow, function(data) { // everything that was here before ... then var xAxis = d3.svg.axis() .scale(x) .orient('bottom') d3.select('.x.axis').call(xAxis) var yAxis = d3.svg.axis() .scale(y) .orient('left') .tickFormat(d3.format('.0')); d3.select('.y.axis').call(yAxis) }) So what have we done? Line 2 - we move the g group to the right to make room for the y axis Line 4-8 - add 2 new g elements for the 2 axes Lines 13-16 - create the x axis using the same scale as the rectangles then tell d3 to apply it to the DOM elements we created before Lines 18-23 - do the same with the y axis http://alexrothenberg.github.com/examples/d3-chart/with-axes.html Now that’s looking pretty good! Let’s keep experimenting and see how to make it more dynamic. Loading different data sets It does more than just snow in Boston, sometimes it rains and its interesting to know how hot or cold it gets. Let’s let people pick what weather statistic they want to look at. 1 2 3 4 5<select onchange="loadData()" id="metric"> <option >snow</option> <option >precipitation</option> <option >temperature</option> </select> There’s our simple select box and now for the javascript changes. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15var loadData = function() { var metric = document.getElementById('metric').selectedOptions[0].text; var dataFile = 'data/' + metric + '.tsv' d3.tsv(dataFile, parseRow, function(data) { // .. unchanged code ... var rect = g.selectAll('.bar').data(data); rect.enter().append('rect'); rect.exit().remove(); // .. more unchanged code ... }) } loadData() Line 1 - we wrap the call to d3.tsv in a new loadData function. Line 2-4 - pick which data file to load (we cannot hardcode ‘data/snow.tsv’ anymore) Lines 7-9 - Remember when we talked about thinking in joins and how d3 binds data to DOM elements? Previously we only had the enter() line which handles the case when there are more rows of data than DOM elements. Now we need to handle the opposite case when there are more DOM elements than rows of data. In that case we use exit() and delete those elements. http://alexrothenberg.github.com/examples/d3-chart/different-statistics.html Animating with the d3 transtions API It’s always fun to have things move around so in our last step we’re going to look at how to rearrange the chart to be in descending order or calendar order. Once again there’s a d3 transition API to help. We’ll start by adding a UI element 1<input type=checkbox>Sort</input> and then add the logic. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32d3.tsv(dataFile, parseRow, function(data) { // .. all the unchanged code ... then var monthIndex = function(monthName) { var months = { Jan: 1, Feb: 2, Mar: 3, Apr: 4, May: 5, Jun: 6, Jul: 7, Aug: 8, Sep: 9, Oct: 10, Nov: 11, Dec: 12 }; return months[monthName]; } d3.select('input').on('change', function() { var sortByAverage = function(a, b) { return b.average - a.average; }; var sortByMonth = function(a, b) { return d3.ascending(monthIndex(a.month), monthIndex(b.month)); }; var sortedMonths = data.sort(this.checked ? sortByAverage : sortByMonth) .map(function(d) { return d.month; }) x.domain(sortedMonths) var transition = svg.transition().duration(750); var delay = function(d, i) { return i * 50; }; transition.selectAll(".bar") .delay(delay) .attr("x", function(d) { return x(d.month); }); transition.select(".x.axis") .call(xAxis) .selectAll("g") .delay(delay); }) }) Line 4 - Bind to the change event so this gets called when the sort checkbox changes Line 5-9 - Sort the months in the right way and update the x domain Line 11-12 - Use the d3.transition API to tell the duration (750 ms) and make the elements start not all at once. Line 14-16 - Animate all the rectangles (they have class .bar) Line18-21 - Aminate the labels on the x axis And that brings us to our final working chart. http://alexrothenberg.github.com/examples/d3-chart/index.html The d3.js API is immense but very well documented and there are tons of examples to inspire you at the D3.js Gallery. Last of all thanks to Mike Bostock for creating such an awesome library.

Lets Get Small: Why I Dislike the Module Include Pattern

over 3 years ago | Alex Rothenberg: Alex Rothenberg

Like many others in the Ruby community I’ve read and been inspired by Sandi Metz’s great book Practical Object-Oriented Design in Ruby. If you haven’t read it yet go out an buy it (right after you finish this article :) There is a lot of information in there but the simple mantra I’ve taken from it is: Smaller is better than Bigger. Small classes Small methods Small number of responsibilities (single responsibility principle) Small files Small number of dependencies Small everything Let's Get Small Let’s Get Small - I try to keep repeating this mantra as I code and find that it results in better, more testable and easier to understand code. We’re going to look at an example that tries to DRY up some code by extracting it into a module that gets included in different classes. Even though it looks like this shrinks the classes we’ll see that it actually doesn’t and is a pattern to be avoided. Let’s imagine we need to record certain events in an audit log. Our application is running on many different places and the audit log lives on a remote server and we post our events using an http api. Simplest straw-man solution The simplest solution is to just put the HTTP post code in each of our classes. 1 2 3 4 5 6 7class MyClass def do_something HTTP.post 'http://api.example.com/audit/log', event: 'I did something' # actually do something end end Reading this you can see the audit trail code on line 3 but its not really clear that that is recording to an audit log. Additionally a real implementation with error handling and additional logic would almost certainly be more than a single line causing a lot of duplication once we copy-and-paste into another class. We need an AuditTrail thing to DRY up the code and make the dependency more explicit. The module include anti-pattern Our first refactor is to create an AuditTrail module and include it in many different classes. I’ve seen this often (heck I’ve written it a lot) but my thinking has evolved and I now avoid it because it violates the keep it small rule. 1 2 3 4 5 6 7 8 9class MyClass include AuditTrail def do_something record_in_audit_trail 'I did something' # actually do something end end You can see on line 2 we include the module and on line 5 we record_in_audit_trail. The included module look like this: 1 2 3 4 5module AuditTrail def record_in_audit_trail(message) HTTP.post 'http://api.example.com/audit/log', event: message end end The good things about this refactor are We now have an AuditTrail module that can be adapt as the implementation grows to more than a single line. Other classes besides MyClass can also use the AuditTrail. So what’s wrong with this design? Well, by including the AuditTrail: We increase the size of each of our classes. Each now responds to its methods and all the methods of the AuditTrail (I know its only 1 in this simple example). We had to adopt a naming convention record_in_audit_trail that hints at where the method is defined. This makes line 5 of MyClass easier to read but makes line 2 of AuditTrail more confusing and harder to read. We’ve decreased the size of each class’ file and extracted common code (both good things) but we haven’t really made the surface area of the class smaller and the dependency on AuditTrail is explicit on line 2 but hidden on line 5. The next refactor solves these problems to keep the surface area of each class small and also make explicit that AuditTrail stuff is the responsibility of the AuditTrail? Make AuditTrail a class Since Ruby is all about classes and sending messages between objects so let’s use create an AuditTrail class. Now our MyClass looks like this 1 2 3 4 5 6 7class MyClass def do_something AuditTrail.record 'I did something' # actually do something end end Its really easy to see on line 3 where it tells the AuditTrail to record the event and the rest of the code is 100% related to its responsibility (doing something). On the AuditTrail side we simply change it from a module to a class and rename its method to record 1 2 3 4 5class AuditTrail def self.record(message) HTTP.post 'http://api.example.com/audit/log', event: message end end Since it is a class we also have the opportunity to extend it as requirements change perhaps using resque or something else so we do our processing in the background. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18class AuditTrail attr_reader :message def initialize(message) @message = message end def self.record(message) new(message).send end def send HTTP.post url, event: message end def url 'http://api.example.com/audit/log' end end What are the advantages of this approach? Each class clearly defines its single responsibility without any pollution from the AuditTrail responsibility. The classes are easier to read as their dependency on AuditTrail is explicit as AuditTrail.add (I believe Sandi Metz would argue that this dependency should be extracted through dependency injection but I’m still struggling with that idea) The AuditTrail class also defines it’s responibility and is free to name its method add instead of add_to_audit_trail. In summary by using a class instead of including a module we keep it small and smaller is better.

How To Unit Test An Angular App.

almost 4 years ago | Alex Rothenberg: Alex Rothenberg

AngularJS has a great testing story - it’s all based on Dependency Injection, the Karma test runner was written by one of its core developers Vojta Jina and it ships with a variety of mocks like the $httpBackend for unit testing requests to remote services. What I haven’t been able to find much of are examples showing how to take advantage of these features when testing an application that does more than just expose objects connected via a rest api. Today we’re going to build a simple Tic-Tac-Toe game writing unit tests along the way. http://alexrothenberg.github.com/examples/tic-tac-toe/v3/index.html Creating our new app This is the boring but necessary part where we need to get all our scaffolding set-up before we can actually start to make our app play Tic Tac Toe. We’re going to use yeoman to create our project. $ yo angular tic-tac-toe After waiting a while for npm to install our modules we’ve got our basic app created and we can go in and run all 0 unit tests. $ grunt test Running "karma:unit" (karma) task INFO [karma]: Karma server started at http://localhost:8080/ INFO [launcher]: Starting browser Chrome WARN [watcher]: Pattern "/Users/alex/blog/test/mock/**/*.js" does not match any file. INFO [Chrome 28.0 (Mac)]: Connected on socket id WfjkRe1_5u5QeZ8upOC2 Chrome 28.0 (Mac): Executed 1 of 1 SUCCESS (0.123 secs / 0.023 secs) Done, without errors. We’re going to add a few testing libraries to our bower.js file in the devDependencies section "devDependencies": { "sinon": "~1.7.3", "chai": "~1.7.2", "sinon-chai": "~2.4.0" } sinon.js so we can build our own mocks and stubs chai lets us use a really nice BDD style syntax for our assertions. sinon-chai adds the chai syntax to our spies, mocks and stubs After we tell bower to install these libraries. $ bower install And we tell karma to use them in our tests by adding these lines to our karma.conf.js karma.conf.js // list of files / patterns to load in the browser files = [ JASMINE, // & other existing files 'app/bower_components/sinon/lib/sinon.js', 'app/bower_components/sinon/lib/sinon/call.js', 'app/bower_components/sinon/lib/sinon/spy.js', 'app/bower_components/sinon/lib/sinon/stub.js', 'app/bower_components/sinon/lib/sinon/match.js', 'app/bower_components/chai/chai.js', 'app/bower_components/sinon-chai/lib/sinon-chai.js', 'test/chai-should.js' ]; One file we need to create ourselves is test/chai-should.js and it contains just 1 line test/chai-should.js chai.should(); We are finally ready to start building our app! Single player Tic-Tac-Toe To get started we’ll build the worlds most boring tic-tac-toe game. A one player game where you can put X’s on the board until it fills up. http://alexrothenberg.github.com/examples/tic-tac-toe/v1/index.html To build this we need 1) the UI, 2) business logic and 3) a controller to glue them together. For the UI we have a 3x3 html table with two angular bindings. { {markAt(0)} } will display the X or O in each space numbered 1-9. ng-click="play(0)" lets us play an X in a space when we click it. views/main.html 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21<div class="hero-unit"> <h1>One Player Tic Tac Toe</h1> <table id="board"> <tr> <td class="top left" ng-click="play(1)">{ {markAt(1)} }</td> <td class="top middle" ng-click="play(2)">{ {markAt(2)} }</td> <td class="top right" ng-click="play(3)">{ {markAt(3)} }</td> </tr> <tr> <td class="center left" ng-click="play(4)">{ {markAt(4)} }</td> <td class="center middle" ng-click="play(5)">{ {markAt(5)} }</td> <td class="center right" ng-click="play(6)">{ {markAt(6)} }</td> </tr> <tr> <td class="bottom left" ng-click="play(7)">{ {markAt(7)} }</td> <td class="bottom middle" ng-click="play(8)">{ {markAt(8)} }</td> <td class="bottom right" ng-click="play(9)">{ {markAt(9)} }</td> </tr> </table> </div> The next step is to build our controller that exposes play and markAt on the scope. This controller delegates to a TicTacToeGame service and the only real logic it contains is that we are playing ‘X’. This is actually how I try to write my controllers in AngularJS, as skinny as I can so they serve mostly as a mapping between the UI and services which make up the business logic. controllers/tic_tac_toe.js 1 2 3 4 5 6 7 8 9 10 11 12angular.module('ticTacToeApp') .controller('TicTacToeCtrl', function ($scope, TicTacToeGame) { $scope.play = function(position) { TicTacToeGame.playAt('X', position) } $scope.markAt = function(position) { return TicTacToeGame.markAt(position); } }); That leads us to the TicTacToeGame service which knows about the board and how to read and write to it. The most interesting thing it does is map board positions 1-9 to array indices 0-8 since our array is 0-based. services/tic_tac_toe_game.js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18angular.module('ticTacToeApp').factory('TicTacToeGame', function () { var board = [ '', '', '', '', '', '', '', '', '' ]; return { markAt: function(position) { return board[position-1]; }, playAt: function(player, position) { board[position-1] = player; } }; }); Even though our controller and service are pretty simple its enough to see some interesting things as we write our first unit test. Now we’re just going to unit test the controller and have it interact with the service so we implicitly test that as well. test/spec/controllers/tic_tac_toe.js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18describe('Controller: TicTacToeCtrl', function () { var scope; // load the controller's module beforeEach(module('ticTacToeApp')); // Initialize the controller and a mock scope beforeEach(inject(function($controller, $rootScope) { scope = $rootScope.$new(); $controller('TicTacToeCtrl', { $scope: scope }); })); it('plays my move', function() { scope.play(4); scope.markAt(4).should.eql('X'); }); }); There’s some angular magic with Dependency Injection going on here so let’s dig through that. Line 5 - We tell angular about our app. This initializes Angular’s dependency injector so it is later able to inject and use our services. Line 8 - Tell Angular’s injector to give us its $controller service and $rootScope Line 9-10 - We create a scope and save it in a local variable for later. Then use the $controller service to create our TicTacToeCtrl controller. Line 13-16 - Finally our test! We call play(4) and ensure position 4 is now marked with an X. At this point there’s a lot of boilerplate to help us write one simple test but in a little bit we’ll be able to take advantage of that Dependency Injection infrastructure to test write some good tests that isolate the services and controllers from each other. Adding the opposing player Its a pretty boring game when you have no one to play against so the next step we’ll take is to add an opposing player. http://alexrothenberg.github.com/examples/tic-tac-toe/v2/index.html In the controller we change it so that every time we play an X in some position we want to other player to play an O where they choose. There’s some more Dependency Injection at work here as we’re using the OtherPlayer service. On line 2 we tell angular we depend on it then on line 6 we let it decide where to move. controllers/tic_tac_toe.js 1 2 3 4 5 6 7 8 9 10angular.module('ticTacToeApp') .controller('TicTacToeCtrl', function($scope, TicTacToeGame, OtherPlayer) { $scope.play = function(position) { TicTacToeGame.playAt('X', position) TicTacToeGame.playAt('O', OtherPlayer.selectMove()) } // $scope.markAt is unchanged from before }); Now its time to write the OtherPlayer service and we have to decide how smart to make it. I’m going to go with not very smart so I can defeat it and enjoy the sweet taste of tic-tac-toe victory! It will find the first open space and go there - even a 4 year old could come up with a better strategy. services/other_player.js 1 2 3 4 5 6 7 8 9 10 11angular.module('ticTacToeApp').factory('OtherPlayer', function (TicTacToeGame) { return { selectMove: function() { for(var i=0; i<9; i++) { if (TicTacToeGame.markAt(i) == '') { return i; } } } } }); When we think about how to test our controller we have a decision to make. We could write a test like 1 2 3 4 5 6 7 8 9 10 11 it('plays my move in 4 then opponent in 1 since it is the first open square', function() { scope.play(4); scope.markAt(4).should.eql('X'); scope.markAt(1).should.eql('O'); }); it('plays my move in 1 then opponent in 2 since it is the first open square', function() { scope.play(1); scope.markAt(1).should.eql('X'); scope.markAt(2).should.eql('O'); }); The problem with this approach is that this controller test now relies on a lot of internal knowledge of the OtherPlayer server and its game strategy. If we decide to change OtherPlayer to make it play a smarter game we’ll have to change this test even though we wouldn’t have changed this controller. To me that violates the “unit” part of a unit test. A test should test a single unit, in this case our controller or our service but not both so a change to one requires a change to only its unit test. Let’s take another approach where we stub out the OtherPlayer service so we can specify how it will behave for the purpose of our test. test/spec/controllers/tic_tac_toe.js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32describe('Controller: TicTacToeCtrl', function () { var scope; var fakeOtherPlayer; // load the controller's module beforeEach(module('ticTacToeApp')); beforeEach(function() { var myMocks = angular.module('MyAppMocks',[]) myMocks.factory('OtherPlayer', function() { return { selectMove: sinon.stub() } }); module("MyAppMocks") }); // Initialize the controller and a mock scope beforeEach(inject(function ($controller, $rootScope, OtherPlayer) { fakeOtherPlayer = OtherPlayer; scope = $rootScope.$new(); $controller('TicTacToeCtrl', { $scope: scope }); })); it('plays my move', function() { fakeotherPlayer.selectMove.returns(5); scope.play(4); scope.markAt(4).should.eql('X'); scope.markAt(5).should.eql('O'); }); }); It looks like it got much longer and more complicated but there are really only 3 new elements. Its easiest to understand if we jump around out of order. First the test (lines 25-30). This is our test where we control how the other play service behaves. otherPlayer is not the real service but just plain Javascript object that contains a sinon stub. For this test we are saying that if it decides to move in position 5 then there will be an ‘O’ in position 5. Now moving up we’ll see how we setup this fake OtherPlayer service. Sinon.JS is a very cool library and I’ve found its explanation of spies, stubs & mocks among the clearest anywhere. Second, creating the fakeOtherPlayer service (lines 8-16). There are three steps here. To start we register a new module MyAppMocks with angular (line 9). Then we We define an OtherPlayer service whose selectMove method is just a sinon stub (lines 10-14). Finally we register MyAppMocks with angular so the dependency injector will find our fake service when we ask for OtherPlayer. Lastly, let Angular’s Dependency Injector use our fake OtherPlayer (lines 19-23). Explicitly we ask for OtherPlayer on line 19 and save it in a local variable on line 20. We also rely on an implicit step that happens on line 22 $controller('TicTacToeCtrl', { $scope: scope });. When angular creates our controller it will also inject the fake OtherPlayer. We cannot see that but this is the key step that ties it all together. Angular’s dependency injector works so that the most recent module takes precedence over older ones which is why the OtherPlayer in MyAppMocks will be found instead of the OtherPlayer in ticTacToeApp. For us this means the one added on line 15 came after the one added on line 6. Since we have tested our controller in isolation from the real OtherPlayer service we have to separately write some tests for it. Here we will rely on the real TicTacToeGame service (since it is so simple) and our tests insure the “first open position” logic. test/spec/services/other_player.js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25describe('Service: OtherPlayer', function () { // load the controller's module beforeEach(module('ticTacToeApp')); var otherPlayer; var ticTacToeGame; beforeEach(inject(function(OtherPlayer, TicTacToeGame) { otherPlayer = OtherPlayer; ticTacToeGame = TicTacToeGame; })); it('select the first space since it is empty', function() { ticTacToeGame.markAt(1).should.eql(''); otherPlayer.selectMove().should.eql(1); }); it('select the third space when first two are not empty', function() { ticTacToeGame.playAt('X', 1) ticTacToeGame.playAt('0', 2) ticTacToeGame.playAt('X', 4) otherPlayer.selectMove().should.eql(3); }); }); We almost have a game now all that’s missing is the thrill of victory when we crush our computerized opponent. Winning and losing http://alexrothenberg.github.com/examples/tic-tac-toe/v3/index.html How do we build this? We’ll just continue what we’ve built so far. First we’ll add our UI for declaring the winner and starting a new game to the html view. views/main.html <h1>Tic Tac Toe</h1> <div> <button ng-click="newGame()">New Game</button> <span ng-show="winner">{ {winner} } has won!!</span> </div> Then we update our controller to support the idea of winning. We’ve added the $scope.newGame function and also added a bunch of logic around playing. Before moving make sure no one has already won and after each move check if someone just won. In order to do that we extracted some helper functions we put inside the controller but do not expose on the scope. As my controllers and services get more complex this is a pattern I often repeat. controllers/tic_tac_toe.js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31angular.module('ticTacToeApp') .controller('TicTacToeCtrl', function($scope, TicTacToeGame, OtherPlayer) { var checkForWinner = function(player) { if (TicTacToeGame.gameOver()) { $scope.winner = player; } } var playAt = function(player, position) { if (!$scope.winner) { TicTacToeGame.playAt(player, position) checkForWinner(player); } } $scope.play = function(position) { if (TicTacToeGame.markAt(position) == '') { playAt('X', position) playAt('O', OtherPlayer.selectMove()) } } $scope.newGame = function() { TicTacToeGame.newGame(); $scope.winner = null } $scope.markAt = // still unchanged from the very beginning }); We relied on TicTacToeGame.newGame() and TicTacToeGame.gameOver() so now have to write them. Again we refactored markAt into a helper function and created a few new ones like newBoard and winningLine. services/tic_tac_toe_game.js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46angular.module('ticTacToeApp').factory('TicTacToeGame', function () { var newBoard = function() { return [ '', '', '', '', '', '', '', '', '' ]; }; var board = newBoard(); var markAt = function(position) { return board[position-1]; }; var winningLine = function(positions) { return markAt(positions[0]) == markAt(positions[1]) && markAt(positions[1]) == markAt(positions[2]) && markAt(positions[0]) != '' }; return { markAt: markAt, playAt: function(player, position) { board[position-1] = player; }, newGame: function() { board = newBoard(); }, gameOver: function() { var possibleThreeInARow = [ [1, 2, 3], [4, 5, 6], [7, 8, 9], // rows [1, 4, 7], [2, 5, 8], [3, 6, 9], // columns [1, 5, 9], [3, 5, 7] // diagonals ] for (var i=0; i<possibleThreeInARow.length; i++) { if (winningLine(possibleThreeInARow[i])) { return true; } } return false; } }; }); Now we can write some new tests in the controller that verify the new behavior we’ve added a newGame clears the board cannot play in occupied position (thanks to my kids for noticing this bug :) knows when I have won does not let us make any moves when the game is over test/spec/controllers/tic_tac_toe.js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35describe('Controller: TicTacToeCtrl', function () { // All the old beforeEach setup remains unchanged it('plays my move and clears board for new game', function() { fakeOtherPlayer.selectMove.returns(3); scope.play(4); scope.markAt(4).should.eql('X') scope.markAt(3).should.eql('O') scope.newGame(); scope.markAt(4).should.eql('') scope.markAt(3).should.eql('') }); it('cannot play over another player', function() { fakeOtherPlayer.selectMove.returns(3); scope.play(4); scope.play(3); scope.markAt(4).should.eql('X') scope.markAt(3).should.eql('O') }); it('knows when I have won', function() { fakeOtherPlayer.selectMove.returns(4); scope.play(1); scope.play(2); scope.play(3); scope.winner.should.eql('X') }); it('does not let us make any moves when the game is over', function() { scope.winner = 'X' scope.play(5); scope.markAt(5).should.eql('') }); }); We have also added some logic to our TicTacToeGame service so we should test that too. What we’ll test is the logic around winning since we had to write non-trivial logic to get that working. test/spec/services/tic_tac_toe_game.js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36describe('Service: TicTacToeGame', function () { beforeEach(module('ticTacToeApp')); var ticTacToeGame; beforeEach(inject(function(TicTacToeGame) { ticTacToeGame = TicTacToeGame; })); describe('.gameOver', function(){ it('knows top row is a winner', function() { ticTacToeGame.playAt('X', 1); ticTacToeGame.playAt('X', 2); ticTacToeGame.playAt('X', 3); ticTacToeGame.gameOver().should.be.true; }); it('knows middle row is a winner', function() { ticTacToeGame.playAt('X', 4); ticTacToeGame.playAt('X', 5); ticTacToeGame.playAt('X', 6); ticTacToeGame.gameOver().should.be.true; }); it('knows diagonal is a winner', function() { ticTacToeGame.playAt('X', 1); ticTacToeGame.playAt('X', 5); ticTacToeGame.playAt('X', 9); ticTacToeGame.gameOver().should.be.true; }); it('knows a row with both players is not a winner', function() { ticTacToeGame.playAt('X', 1); ticTacToeGame.playAt('O', 2); ticTacToeGame.playAt('X', 3); ticTacToeGame.gameOver().should.be.false; }); }) }); If you want to look at the example we’ve built its all on github alexrothenberg/angular-tic-tac-toe. I hope you’ve found this journey useful and will make sure to test the next Angular app you write!

The "Magic" behind AngularJS Dependency Injection

over 4 years ago | Alex Rothenberg: Alex Rothenberg

If you’ve built anything with AngularJS you know there’s a lot of “magic” that you can usually ignore because it just works. One of the most magical parts for me is dependency injection. Just by adding a parameter to your controller function you suddenly get access to a powerful Angular service. It’s really pretty amazing but you sorta just have to trust it … until something goes wrong. It turns out one easy way to break an AngularJS app is to minify your javascript. This happened to me when I deployed my app to production. The Angular app was being served from a Rails application and Rails automatically minifies javascript in prodution. It turns out there’s a simple and a well documented fix in their tutorial (search for “A Note on Minification”) that boils down to “use an array of parameter names” but it wasn’t clear to me why it worked. In the rest of this article we’re going to Build a simple AngularJS application See how magical dependency injection is Investigate how dependency injection is implemented in AngularJS Break our app by minifying the javascript Understand how the fix works An AngularJS application using the GitHub API We’re going to build a simple AngularJS app that uses the GitHub API to find the most recent commits on the angular.js project. http://alexrothenberg.github.com/examples/angularjs_dependency_injection/index.html Here’s the source for that page: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25<html ng-app> <head> <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.4/angular.js"></script> <script> var MyController = function($scope, $http) { $http.get('https://api.github.com/repos/angular/angular.js/commits') .success(function(commits) { $scope.commits = commits }) } </script> </head> <body ng-controller="MyController"> <h1>Recent commits to AngularJS</h1> <ul> <li ng-repeat="commit in commits"> {{ commit.commit.committer.date | date }} <a ng-href="https://github.com/angular/angular.js/commit/{{commit.sha}}">{{ commit.sha }}</a> {{ commit.commit.message }} </li> </ul> </body> </html> Let’s walk through what’s going on here: Line 1 - The ng-app attribute tells angular to treat this page as an angular app. Line 6-11 - Some JavaScript that defines the controller and tell angular to “inject” the $scope and $http services. Line 15 - The ng-controller="MyController" attribute tells angular the body tag will be scoped by the MyController controller. Line 18-22 - This section will be expanded to many li elements in the DOM, each containing information about one commit. This is pretty cool. Of course not everyone is a fan, in Dependency injection is not a virtue DHH argues that it is a legacy of the Java language that is unnecessary in Ruby (and I suspect he would argue JavaScript). AngularJS is figuring out what the hash part of the url is and automatically inserting it in the page. Dependency Injection is magical So where does dependency injection come in? Here’s where it gets weird… let’s try reordering the arguments in the controller function. var MyController = function($http, $scope) { $http.get('https://api.github.com/repos/angular/angular.js/commits') .success(function(commits) { $scope.commits = commits }) } We changed function($scope, $http) to function($http, $scope) and surprisingly it still works! http://alexrothenberg.github.com/examples/angularjs_dependency_injection/args_swapped.html What seems to be going on as it runs is AngularJS Knows what services our controller function needs in each parameter slot (originally $scope first & $http second now $http first & $scope second). Decides what object should “provide” each of the named services (eg. $httpProvider provides $http). Calls our controller with the appropriate providers in each slot (either MyController(scope, $httpProvider) or MyController($httpProvider, scope)). How does Angular do step #1? In JavaScript the order of the parameters is important and the names do not matter to the caller (see this egghead.io video: $scope vs. scope) Let’s take a look at some straight JavaScript and convince ourselves this is true. If we define a function divide that takes two arguments var divide = function(numerator, denominator) { return numerator / denominator; } As expected divide(1, 2) == 0.5. http://alexrothenberg.github.com/examples/angularjs_dependency_injection/divide.html When we change the order of the parameters, we also change the definition of the function. var divide = function(denominator, numerator) { return numerator / denominator; } Now the definition has changed and divide(1, 2) == 2 http://alexrothenberg.github.com/examples/angularjs_dependency_injection/divide_args_swapped.html It seems Angular is going above and beyond what JavaScript the language supports. How Dependency Injection implements Named Parameters in JavaScript We saw that Angular’s dependency injection relies on the name of the parameters not their order which is a language feature called named parameters that does not exist in JavaScript. How do they do it? AngularJS makes clever use of the fact that every object in JavaScript has a toString function to parse and extract the names of the parameters before deciding what arguments to call your controller function with. Let’s play around with toString and get a feel of how it works. On function objects it returns the source code definition of the object, including the function signature with the names of the parameters. When we call it on our divide function we can see this in action, divide.toString() == "function (numerator, denominator) { return numerator / denominator; }" http://alexrothenberg.github.com/examples/angularjs_dependency_injection/divide_toString.html Angular takes this to the next level in a function called annotate in injector.js that takes a function and returns the names of its parameters. 1 2 3 4 5 6 7 8 9 10 11$inject = []; fnText = fn.toString().replace(STRIP_COMMENTS, ''); argDecl = fnText.match(FN_ARGS); forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg){ arg.replace(FN_ARG, function(all, underscore, name){ $inject.push(name); }); }); fn.$inject = $inject; // ... return $inject; line 2 - use the toString() trick to get the function definition. line 3 - do regular expression pattern matching FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m to find the function signature. line 4-8 - loop through all the parameters and save their names in an array. line 11 - return the array or parameter names. We can see this in action with our trusty divide function, angular.injector().annotate(divide) == ["numerator", "denominator"] http://alexrothenberg.github.com/examples/angularjs_dependency_injection/divide_annotate.html Minification breaks our App The technique of using toString has a big problem. We often minify our javascript before sending it to the browser, in my case the Rails asset pipeline was configured to automatically do this in the production environment. // whitespace re-added for readability var MyController = function(e,t) { t.get("https://api.github.com/repos/angular/angular.js/commits") .success(function(t) { e.commits=t }) } When minified the parameter names are mangled to e or t so cannot be mapped to service names by angular. How can it know that t should be implemented by the $httpProvider or that e is the $scope? http://alexrothenberg.github.com/examples/angularjs_dependency_injection/minified_broken.html In fact if you open the minified_broken.html example and look at the console you will see the error Error: Unknown provider: eProvider <- e. Angular’s annotate function is sophisticated enough to handle minification, in fact, I only showed part of it before. When we look at the whole thing, we see it can annotate a function or an array of parameter name strings followed by a function. In the array form, the first string names the first argument, the second string names the second, etc. and the actual names of the parameters are unimportant. function annotate(fn) { var $inject, fnText, argDecl, last; if (typeof fn == 'function') { if (!($inject = fn.$inject)) { // omitting the code we saw before } } else if (isArray(fn)) { last = fn.length - 1; assertArgFn(fn[last], 'fn') $inject = fn.slice(0, last); } else { assertArgFn(fn, 'fn', true); } return $inject; } When we can now redefine our MyController var MyController = ['$scope', '$http', function($scope, $http) { $http.get('https://api.github.com/repos/angular/angular.js/commits') .success(function(commits) { $scope.commits = commits }) }] When it is minified the strings are not touched so annotate will still work. var MyController= ["$scope", "$http", function(e,t) { t.get("https://api.github.com/repos/angular/angular.js/commits") .success(function(t) { e.commits=t }) }] We can see the annotate function parsing this array angular.injector().annotate(MyController) == ["$scope", "$http"] http://alexrothenberg.github.com/examples/angularjs_dependency_injection/minified_annotate.html Of course what really matters is that it works on the page - which it does. http://alexrothenberg.github.com/examples/angularjs_dependency_injection/minified_working.html If you’ve made it to the end of this long post, I hope you’ve enjoyed the journey into how AngularJS knows what services to inject in your controllers. Again all you really need to know is to use an array naming the parameters followed by your function but I hope you enjoyed learning how it actually works. I know I did!

Combining D3 and Ember to Build Interactive Maps

about 5 years ago | Alex Rothenberg: Alex Rothenberg

The Javascript world is exploding with new libraries that let us build really interactive applications. The image on the left is a static image showing how each US State voted in the 2008 Presidential Election - I suspect we’ll be seeing a lot more of this map in the coming months! Let’s look at how we can draw that map ourselves and make it interactive using: * SVG - a vector graphics format. That will let us draw an good looking map using publicly available data about the geography of each state. * D3.js - a JavaScript library for manipulating documents based on data. Its super fast and will help us interact with the SVG map. * Ember.js - a JavaScript framework for creating ambitious web applications that eliminates boilerplate and provides a standard application architecture. Its going to keep us disciplined and our code organized. An outline map of the States in the USA We’ll get stated building an Ember app to draw a map of the USA with each state outlined. First, we’ll need to know what each State looks like. This information is available to download from http://data.jquerygeo.com/usastates.json. var MapApp.usaStatesGeoData = { "type":"FeatureCollection", "features":[ {"type":"Feature", "properties":{"fips":8,"name":"Colorado","abbr":"CO"}, "geometry":/*...one polygon defining a rectangular shape...*/}, {"type":"Feature", "properties":{"fips":22,"name":"Louisiana","abbr":"LA"}, "geometry":/*...many polygons defining a very complicated coastline */}, // all the other States are here too ... ] }; This is a GeoJSON format which Thomas Newton points out in his post Positioning and Scaling maps in D3 is a format that works really well with D3 since it is data that can be rendered into SVG by our code. Each State’s boundaries are defined in complete detail with polygons that a cartographer has drawn out for us. This works for rectangular States like Colorodo or Wyoming and amazingly also works for those with lots of coastline like Louisiana or Alaska (although the polygons are much more complicated). Now, to create an Ember app we need to create our application and we’ll assign the GeoJSON data into a bindable property. window.MapApp = Ember.Application.create({ ready: function() { this.set('usaStatesGeoData', usaStatesGeoData); } }); Next we’ll add some handlebars expressions to our html page telling it to display the map as an Ember View (we’ll create that in a minute). <script type='text/x-handlebars'> { {view MapApp.Map geoDataBinding="MapApp.usaStatesGeoData"} } </script> Finally we write the view MapApp.Map = Ember.View.extend({ didInsertElement: function() { var elementId = this.get('elementId'); var regions = d3.select("#" + elementId).append("svg").append("g").attr("id", "regions"); var features = this.get('geoData').features; var path = this.get('path'); regions.selectAll("#regions path").data(features).enter().insert("path") .attr("d", path) .attr('stroke', '#ccc' ) .attr('fill', 'white' ); } path: function() { var mapW = this.$().height(); var mapH = this.$().width(); var mapXY = d3.geo.albersUsa().scale(1000).translate([mapH/2,mapW/2]); return d3.geo.path().projection(mapXY); }.property(), }); Whew that is a bit of code so let’s dig in. This is where we use d3 to create the svg that looks like a map of the USA. d3 (Data-Driven Documents) works by binding data to your DOM then applying tranformations to that data. In this case our data is the GeoJSON file and our tranformations turn it into an SVG map. didInsertElement is called by Ember when the view is inserted into the page’s DOM. The first two lines use d3.select to add the <svg><g id="regions"> elements to the page on this view’s portion of the page. The remaining use d3.selectAll.data.enter to loop through the features (each State) and add a <path> element. Looping through each feature (ie. State), we make use of the rest of the code and set the d attribute to the value of the path property. The path logic scales the map and uses the albersUsa projection which moves Alaska and Hawaii to the bottom left where we usually see them on maps. Looking at code is fun but what does it look like? Below is the page we just built and the you can see that it does, in fact, look like a map of the USA with each State outlined. http://www.alexrothenberg.com/examples/ember-d3maps/map_outline.html Coloring the States red or blue A red/blue map isn’t much use when all the States are white so let’s color them in. First we’ll need some data with the election results so we know what color each State should be. There’s a source from Google at http://code.google.com/p/general-election-2008-data/source/browse/trunk/json/votes/2008. I found the format to be a little hard to work with so I processed it into a simpler json file with just the information we’ll need. It looks like: [ {"name": "Alabama", "electoral": 9, "winner": "McCain"}, {"name": "Alaska", "electoral": 3, "winner": "McCain"}, {"name": "Arizona", "electoral": 10, "winner": "McCain"}, {"name": "Arkansas", "electoral": 6, "winner": "McCain"}, {"name": "California", "electoral": 55, "winner": "Obama"}, // results for the rest of the States too... ] To use it we’ll save it in our Ember Application. window.MapApp = Ember.Application.create({ ready: function() { this.set('usaStatesGeoData', usaStatesGeoData); var stateResults = usaPres2008Data.map(function(stateResult) { return MapApp.StateResult.create(stateResult); }); this.set('usaPres2008Results', MapApp.StateResults.create({content: stateResults})); } }); We use the javascript map function to turn our json data into ember objects that we can put into an Ember ArrayProxy object. For this example we don’t really need these ember objects but in a real application we’d probably get some requirements that would make them useful. For instance if we wanted the colors to update on election night as new results come in. Since we are using the StateResult and StateResults objects, we need to define them next. MapApp.StateResult = Ember.Object.extend({}); MapApp.StateResults = Ember.ArrayProxy.extend({ names: (function() { return this.mapProperty('name'); }).property('content'), findByName: function(name) { var content = this.get('content'); var index = this.get('names').indexOf(name); return content[index]; } }); Both objects are pretty simple. In fact they would both be empty except for the findByName accessor we define on StateResults. We’ll see the need for that in a minute when we look at how the view decides whether to color a State red or blue. This takes us to the view which enhances what we had before: MapApp.Map = Ember.View.extend({ // the path property is unchanged didInsertElement: function() { // same code as before ... regions.selectAll("#regions path").data(features).enter().insert("path") .attr("d", path) .attr('stroke', '#ccc') .attr('fill', this.updateFillFor ); // This line changed }, // A new function updateFillFor: function(d) { var stateResult = MapApp.usaPres2008Results.findByName(d.properties.name); switch (stateResult.get('winner')) { case 'Obama': return 'blue'; case 'McCain': return 'red'; } } }); Most of the view is the same, all that’s different is the way we set the fill on each State (“feature” in d3 terms). .attr('fill', this.updateFillFor); - Instead of setting the “fill” attribute to ‘white’ for all States we now provide a function to make the decision differently for each State. D3 will call the function with the current State as an argument (it actually passes the D3 “datum” object). updateFillFor - This function uses the findByName function we defined in StateResults to match the “geographical” State with the “election result” State. They are separate because each came from a different external json source. Once we have the stateResult object we look at the winner and know to return either “red” or “blue”. We can see it all working together right here and yes it does look like all the other red/blue election maps you’ve seen. http://www.alexrothenberg.com/examples/ember-d3maps/map_red_blue.html This is just the beginning of what you can do by combining D3.js with Ember.js. Next I plan to write about how you could add behavior like clicking to select a State and let Ember show details about that State.

Closures can provide encapsulation when Creating Objects in Javascript

over 5 years ago | Alex Rothenberg: Alex Rothenberg

Objects are funny things in Javascript. If you’re coming from a language like Ruby with classical inheritance you’ll probably be surprised that in Javascript’s prototype system there are no such things as classes. The patterns are different but we can still achieve what’s important about object oriented software namely objects that encapsulate data and behavior. Today I’m going to show you two different ways we can create a simple database object that supports the basic CRUD operations in Javascript. Object Literal The simplest way to create our database is to just declare it as a singleton object with some instance data and functions. We’ll use the “starts with underscore” naming convention to denote “private” data but that is just a convention and not enforced. var Database = { _data: {}, create: function(object) { return this._data[object.id] = object }, read: function(id) { return this._data[id] }, update: function(object) { return this._data[object.id] = object }, delete: function(id) { return this._data[id] = null } } This is pretty simple and if you try it out you’ll see it actually works. Try it at http://jsfiddle.net/alexrothenberg/Tn8uq/ // We can CREATE Database.create({id: 7, name: 'Alex'}); Database.create({id: 9, name: 'Pat'}); // We can READ console.log('7: ' + Database.read(7).name); // 7: Alex console.log('9: ' + Database.read(9).name); // 9: Pat // We can UPDATE Database.update({id: 7, name: 'Alexander'}) console.log('7: ' + Database.read(7).name); // 7: Alexander // We can DELETE Database.delete(7) console.log('7: ' + Database.read(7)); // 7: null The biggest downside of this approach is that there is no encapsulation. We can get at the _data instance variable directly to read or change it. Database._data[7] = {name: 'I changed your name'} console.log('7: ' + Database.read(7).name); Encapsulation via a Closure By wrapping our Database in a closure we can encapsulate our private functions and data. The way to read this is that Database is a function that defines a closure. The variables within that closure have access to each other (i.e. _create has access to _data). When the Database is called it returns an object that explicitly exposes 4 functions and nothing else. var Database = (function() { _data = {} _create = function(object) { return _data[object.id] = object } _read = function(id) { return _data[id] } _update = function(object) { return _data[object.id] = object } _delete = function(id) { return _data[id] = null } return { create: _create, read: _read, update: _update, delete: _delete } }).call(this) When we test it we see that it still works. Try it at http://jsfiddle.net/alexrothenberg/kcGLK/ // We can CREATE Database.create({id: 7, name: 'Alex'}); Database.create({id: 9, name: 'Pat'}); // We can READ console.log('7: ' + Database.read(7).name); // 7: Alex console.log('9: ' + Database.read(9).name); // 9: Pat // We can UPDATE Database.update({id: 7, name: 'Alexander'}) console.log('7: ' + Database.read(7).name); // 7: Alexander // We can DELETE Database.delete(7) console.log('7: ' + Database.read(7)); // 7: null The _data is encapsulated and not accessible from the outside console.log(Database._data) // undefined There are other patterns for working with objects in Javascript that take advantage of Javascript’s prototype system but I don’t have time to go into that today … perhaps in a future post.

Building a Browser IDE

over 5 years ago | Alex Rothenberg: Alex Rothenberg

Its become so easy to share code examples as gists but once you start sharing html, css or javascript you can do so much more than share static code. Browsers can run html, css and javascript so we can actually run the code we’re sharing. Let’s look at how we could build a simple IDE in your browser like jsfiddle where where you can experiment with your HTML, CSS and Javascript. HTML IDE First we’re going to build an HTML editor. Try it out…I’ll wait. .demo { width:80%; margin:auto; margin-bottom:1em; } .demo iframe { width: 100%; border: 5px inset; } How does it work? We need three things. 1 - A textarea where you can type in the html <textarea id="html" class="content"> Hi there this is some <b>bold</b> content and this is <i>italic</i>. <p>Pretty cool huh!</p> <p>What else can you type?</p> </textarea> 2 - An iframe to preview the page <iframe id="preview" class="content"></iframe> 3 - Some javascript to copy the html from the text area into the div $('#html').keypress(function() { $('#preview').contents().find('html').html($(this).val()) }) After we add some formatting and put it all together we get a page like this. http://www.alexrothenberg.com/examples/browser_ide/html_ide.html <html> <head> <meta charset=utf-8> <title>Browser IDE</title> <link rel="stylesheet" href="./styles.css" type="text/css" charset="utf-8"> <script src="jquery.min.js"></script> <script type='text/javascript'> $(function() { $('#html').keyup(function() { $('#preview').contents().find('body').html($(this).val()) }) $('#html').keyup() // Initialize }) </script> </head> <body> <h1>Edit the HTML and see it in the Preview</h1> <div class="box"> <div class="label">HTML</div> <textarea id="html" class="content"> Hi there this is some <b>bold</b> content and this is <i>italic</i>. <p>Pretty cool huh!</p> <p>What else can you type?</p> </textarea> </div> <div class="box"> <div class="label">Preview</div> <iframe id="preview" class="content"></iframe> </div> </body> </html> HTML and CSS IDE HTML is good but any self respecting webpage will also have a CSS file. We can add that too. To get this working we added 1 - A new textarea where you can type in the css <textarea id="css" class="content"> .warning { color: red; } </textarea> 2 - Some javascript to copy the css from the text area into the div $('#css').keypress(function() { preview_contents.find('head style').remove() preview_contents.find('head').append("<style>" + $(this).val() + "</style>") }) All put together it looks like this. http://www.alexrothenberg.com/examples/browser_ide/html_css_ide.html <html> <head> <meta charset=utf-8> <title>Browser IDE</title> <link rel="stylesheet" href="./styles.css" type="text/css" charset="utf-8"> <script src="jquery.min.js"></script> <script type='text/javascript'> $(function() { var preview_contents = $('#preview').contents() $('#html').keyup(function() { preview_contents.find('body').html($(this).val()) }) $('#css').keyup(function() { preview_contents.find('head style').remove() preview_contents.find('head').append("<style>" + $(this).val() + "</style>") }) $('#html').keyup() // Initialize $('#css').keyup() // Initialize }) </script> </head> <body> <h1>Edit HTML and CSS</h1> <div class="box"> <div class="label">HTML</div> <textarea id="html" class="content"> <div class="warning">This is a warning!</div> <div class="message">This is a message.</div> </textarea> </div> <div class="box"> <div class="label">CSS</div> <textarea id="css" class="content"> .warning { color: red; } /* Try adding a .message style. Make it bold. */ </textarea> </div> <div class="box"> <div class="label">Preview</div> <iframe id="preview" class="content"></iframe> </div> </body> </html> HTML, CSS and Javascript IDE So the last part of the page we want to edit is javascript. We implement this following the same pattern we’ve been using. 1 - A new textarea where you can type in the javascript <textarea id="javascript" class="content"> // Change the next line and watch the preview change var new_text = 'This text was added by js' var js_element = document.getElementById('js_content') js_element.innerHTML = new_text </textarea> 2 - Some javascript to copy the css from the text area into the div $('#javascript').keypress(function() { preview_contents.find('head script').remove() var created_script = preview_contents[0].createElement('script'); created_script.text = $(this).val() preview_contents.find('head')[0].appendChild(created_script) }) Here’s the complete page. http://www.alexrothenberg.com/examples/browser_ide/html_css_js_ide.html <html> <head> <meta charset=utf-8> <title>Browser IDE</title> <link rel="stylesheet" href="./styles.css" type="text/css" charset="utf-8"> <script src="jquery.min.js"></script> <script type='text/javascript'> $(function() { var preview_contents = $('#preview').contents() $('#html').keyup(function() { preview_contents.find('body').html($(this).val()) $('#javascript').keyup() // let the javascript change the page }) $('#css').keyup(function() { preview_contents.find('head style').remove() preview_contents.find('head').append("<style>" + $(this).val() + "</style>") }) $('#javascript').keyup(function() { preview_contents.find('head script').remove() var created_script = preview_contents[0].createElement('script'); created_script.text = $(this).val() preview_contents.find('head')[0].appendChild(created_script) }) $('#html').keyup() // Initialize $('#css').keyup() // Initialize $('#javascript').keyup() // Initialize }) </script> </head> <body> <h1>Edit HTML, CSS and Javascript</h1> <div class="box"> <div class="label">HTML</div> <textarea id="html" class="content"> <div class="warning">This is a warning!</div> <div class="message">This is a message</div> <div id="js_content"></div> </textarea> </div> <div class="box"> <div class="label">CSS</div> <textarea id="css" class="content"> .warning { color: red; } </textarea> </div> <div class="box"> <div class="label">Javascript</div> <textarea id="javascript" class="content"> // Change the next line and watch the preview change var new_text = 'This text was added by js' var js_element = document.getElementById('js_content') js_element.innerHTML = new_text </textarea> </div> <div class="box"> <div class="label">Preview</div> <iframe id="preview" class="content"></iframe> </div> </body> </html> Syntax highlighting We now have a very simple IDE but its missing something all code editors have. No I don’t mean “save”, although that is important I’m going to ignore it. When I’m typing text it all starts to run together and become really hard to read. It would be so much easier if we had some syntax highlighting. We’re going to use a javascript library called CodeMirror which knows how to syntax highlight html, css, javascript and a ton of other languages. When we’re done it will be much easier to read our code We’ll add CodeMirror in these 3 steps. 1 - First we download CodeMirror and save it along with our files. 2 - Now we need to add it to our page <link rel="stylesheet" href="./codemirror/codemirror.css"> <script src="./codemirror/mode/javascript/javascript.js"></script> <script src="./codemirror/mode/css/css.js"></script> <script src="./codemirror/mode/xml/xml.js"></script> <script src="./codemirror/mode/htmlmixed/htmlmixed.js"></script> 3 - Finally some javascript that enables CodeMirror on our three textareas. Here’s the code for the html pane. CodeMirror.fromTextArea($('#html')[0], { mode: "htmlmixed", matchBrackets: true, onChange: function(editor) { copyHTML(editor.getValue()) } }) var copyHTML = function(html_text) { preview_contents.find('html').html(html_text) copyJavascript($('#javascript').val()) // let the javascript change the page } copyHTML($('#html').val()) // Initialize CodeMirror actually offers a ton more functionality than just syntax highlighting like emacs or vim keybinding, matching parentheses, undo, and more that you can investigate if you’re interested. When we’re done with all that we have this single page app. http://www.alexrothenberg.com/examples/browser_ide/index.html <html> <head> <meta charset=utf-8> <title>Browser IDE</title> <link rel="stylesheet" href="./styles.css" type="text/css" charset="utf-8"> <script src="jquery.min.js"></script> <script src="./codemirror/codemirror.js"></script> <link rel="stylesheet" href="./codemirror/codemirror.css"> <script src="./codemirror/mode/javascript/javascript.js"></script> <script src="./codemirror/mode/css/css.js"></script> <script src="./codemirror/mode/xml/xml.js"></script> <script src="./codemirror/mode/htmlmixed/htmlmixed.js"></script> <script type='text/javascript'> $(function() { var preview_contents = $('#preview').contents() CodeMirror.fromTextArea($('#html')[0], { mode: "htmlmixed", matchBrackets: true, onChange: function(editor) { copyHTML(editor.getValue()) } }) CodeMirror.fromTextArea($('#css')[0], { mode: "css", matchBrackets: true, onChange: function(editor) { copyCSS(editor.getValue()) } }) CodeMirror.fromTextArea($('#javascript')[0], { mode: "javascript", matchBrackets: true, onChange: function(editor) { copyJavascript(editor.getValue()) } }) var copyHTML = function(html_text) { preview_contents.find('body').html(html_text) copyJavascript($('#javascript').val()) // let the javascript change the page } var copyCSS =function(css_text) { preview_contents.find('head style').remove() preview_contents.find('head').append("<style>" + css_text + "</style>") } var copyJavascript =function(javascript_text) { preview_contents.find('head script').remove() var created_script = preview_contents[0].createElement('script'); created_script.text = javascript_text preview_contents.find('head')[0].appendChild(created_script) } copyHTML($('#html').val()) // Initialize copyCSS($('#css').val()) // Initialize copyJavascript($('#javascript').val()) // Initialize }) </script> </head> <body> <h1>Edit HTML, CSS and Javascript with Syntax Highlighting</h1> <div class="box"> <div class="label">HTML</div> <textarea id="html" class="content"> <div class="warning">This is a warning!</div> <div class="message">This is a message</div> <div id="js_content"></div> </textarea> </div> <div class="box"> <div class="label">CSS</div> <textarea id="css" class="content"> .warning { color: red; } </textarea> </div> <div class="box"> <div class="label">Javascript</div> <textarea id="javascript" class="content"> // Change the next line and watch the preview change var new_text = 'This text was added by js' var js_element = document.getElementById('js_content') js_element.innerHTML = new_text </textarea> </div> <div class="box"> <div class="label">Preview</div> <iframe id="preview" class="content"></iframe> </div> </body> </html> This entire sample we’ve built is on github at https://github.com/alexrothenberg/alexrothenberg.github.com/tree/master/examples/browser_ide.

Testing IP Whitelisting in your Specs and Features

over 5 years ago | Alex Rothenberg: Alex Rothenberg

Rails has so much support for testing built into itself that its rare I come up with something that’s hard to test but HTTP headers is not easy. Normally you don’t have to worry about HTTP headers as they’re set by the browser and you don’t do much with them. Recently I was working on an application where each user has an IP whitelist and they are only allowed to come from their whitelisted IP addresses. This isn’t as crazy as it sounds since the app is in a corporate environment and the users will all be coming from their corporate networks. Basically this means our authentication method needs 3 pieces of information username password remote ip address What makes this interesting is that the first two are input by the user but the ip address comes from the browser and network. Writing an RSpec unit test or Cucumber scenario to test user parameters (username and password) is something we’ve all done before but today I’m going to talk about how you can also test the IP address in a header. Implementation Before we look at how to test this let’s take a look at the implementation of our SessionController. app/controllers/sessions_controller.rb class SessionsController < ApplicationController def new @session = Session.new end def create remote_ip_address = request.headers['X-Forwarded-For'] || request.headers['REMOTE_ADDR'] @session = Session.create(params[:username], params[:password], remote_ip_address) if @session.valid? session[:current_user] = @session.user redirect_to root_url else flash.now[:error] = 'Unable to authenticate. Please try again' render :new end end def destroy session[:current_user] = nil redirect_to session end end These three actions provide login and logout. new displays the login form with username & password fields create uses the username and password from the form as well as the ip address to create a session (i.e. authenticate). In case the request hops through some proxy servers we use the X-Forwarded-For header to get the source IP and not the proxy’s IP. destroy users need to log out (but we wont talk about that anymore here) This works, but you shouldn’t trust me. We need tests around the create action! Unit Testing the IP Whitelist with RSpec Our Controller Spec needs to pass all 3 pieces of information (username, password & ip address) to the controller. Passing the username and password is pretty standard and something I’m sure you’ve done before. They come from a form so we pass them as a hash in the second argument to post. spec/controllers/sessions_controller_spec.rb post :create, {:username => 'alex', :password => 'secret'} Unfortunately we can’t pass the IP the same way because the post method in ActionController::TestCase doesn’t support passing headers in (but it does take the session or flash - that’s interesting to remember for some other time). actionpack/lib/action_controller/test_case.rb def post(action, parameters = nil, session = nil, flash = nil) process(action, parameters, session, flash, "POST") end If we keep looking around it turns out the ActionDispatch::TestRequest object has a nice convenience method that lets us specify the remote_addr directly. actionpack/lib/action_dispatch/testing/test_request.rb def remote_addr=(addr) @env['REMOTE_ADDR'] = addr end If we add a line to our spec we can handle the case where the IP comes in the REMOTE_ADDR HTTP header. spec/controllers/sessions_controller_spec.rb request.remote_addr = '192.168.1.100' post :create, {:username => 'alex', :password => 'secret'} We still need to deal with the X-Forwarded-For case. While Rails doesn’t give us a convenience method, by looking at the implementation of the remote_addr= method we can see how to set this header ourselves. spec/controllers/sessions_controller_spec.rb request.env['X-Forwarded-For'] = '192.168.1.100' post :create, {:username => 'alex', :password => 'secret'} Putting it all together we end up with a controller spec that looks like this. spec/controllers/sessions_controller_spec.rb require 'spec_helper' describe SessionsController do describe '#create' do describe 'successfully' do let(:alex) { mock } let(:valid_session) { mock(:valid? => true, :user => alex )} before do Session.should_receive(:create).with('alex', 'secret', '192.168.1.100').and_return(valid_session) end describe 'using REMOTE_ADDR' do before do request.remote_addr = '192.168.1.100' post :create, {:username => 'alex', :password => 'secret'} end it { should redirect_to root_path } it { should set_session(:current_user).to(alex)} end describe 'using X-Forwarded-For' do before do request.remote_addr = '172.16.254.1' request.env['X-Forwarded-For'] = '192.168.1.100' post :create, {:username => 'alex', :password => 'secret'} end it { should redirect_to root_path } it { should set_session(:current_user).to(alex)} end end describe 'unsuccessfully' do let(:invalid_session) { mock(:valid? => false) } before do Session.should_receive(:create).with('alex', 'secret', '192.168.1.100').and_return(invalid_session) end describe 'using REMOTE_ADDR' do before do request.remote_addr = '192.168.1.100' post :create, {:username => 'alex', :password => 'secret'} end it { should render_template :new } end describe 'using X-Forwarded-For' do before do request.remote_addr = '172.16.254.1' request.env['X-Forwarded-For'] = '192.168.1.100' post :create, {:username => 'alex', :password => 'secret'} end it { should render_template :new } end end end end To sum up we can pass parameters as a hash in the post method post :create, {:username => 'alex', :password => 'secret'} set the remote_addr on the request with a convenience method request.remote_addr = '192.168.1.100' et the X-Forwarded-For directly on the requests’s environment hash request.env['X-Forwarded-For'] = '192.168.1.100' Integration Testing the IP Whitelist in a Cucumber Feature We face a similar issue when writing our cucumber scenarios - its easy to pass the username and password but harder to pass the IP address. The solution turns out to be similar but not quite exactly the because our Cucumber steps will use Capybara instead of ActionController::TestCase directly. Before we look into how to implement the steps, let’s write the feature we want which will help us define the steps we need. features/authentication.feature Feature: Authentication of a user In order to ensure a really secure application As a user I want my IP address to be validated during login Background: Given the following user exists: | username | password | company | | alex | secret | ip_address: 192.168.1.100 | Scenario: Successful log in Given I am connecting from ip "192.168.1.100" When I log in as "alex" with password "secret" Then I should be on the home page Scenario: Successful log in with X-Forwarded-For header Given I am connecting from ip "192.168.1.100" behind a proxy When I log in as "alex" with password "secret" Then I should be on the home page Scenario: Failed log in from wrong IP Given I am connecting from ip "172.16.254.1" When I log in as "alex" with password "secret" Then authentication should have failed Scenario: Failed log in from wrong IP behind a proxy Given I am connecting from ip "172.16.254.1" behind a proxy When I log in as "alex" with password "secret" Then authentication should have failed We immediately realize we don’t know how to write the first step features/step_definitions/authentication_steps.rb Given /^I am connecting from ip "([^"]*)"$/ do |ip_address| pending # How do we set the IP Address??? end To figure this out we need to dig into how capybara works. We don’t call post in ActionController::TestCase directly instead letting capybara do it for us. To see what capybara is doing we can skip that step and implement the login step features/step_definitions/authentication_steps.rb Given /^I am connecting from ip "([^"]*)"$/ do |ip_address| # do nothing for now end When /^I log in as "([^"]*)" with password "([^"]*)"$/ do |name, password| visit(new_session_path) fill_in('User name', :with => name) fill_in('Password', :with => password) click_button('Log In') end and edit the SessionsController to show us the stack trace. app/controllers/sessions_controller.rb class SessionsController < ApplicationController def create raise caller.inspect end end The stack trace is very big but if we look closely, somewhere in the middle of it we see lines below that show how capybara uses the rack-test gem to submit our form. ~/.rvm/gems/ruby-1.8.7-p334/gems/rack-test-0.6.1/lib/rack/test.rb:66:in `post' ~/.rvm/gems/ruby-1.8.7-p334/gems/capybara-1.1.2/lib/capybara/rack_test/browser.rb:62:in `send' ~/.rvm/gems/ruby-1.8.7-p334/gems/capybara-1.1.2/lib/capybara/rack_test/browser.rb:62:in `process' ~/.rvm/gems/ruby-1.8.7-p334/gems/capybara-1.1.2/lib/capybara/rack_test/browser.rb:27:in `submit' ~/.rvm/gems/ruby-1.8.7-p334/gems/capybara-1.1.2/lib/capybara/rack_test/form.rb:64:in `submit' ... more lines omitted... ~/.rvm/gems/ruby-1.8.7-p334/gems/capybara-1.1.2/lib/capybara/node/actions.rb:38:in `click_button' Looking at the Rack::Test#post method we see something similar to what we saw before in ActionController::TestCase but its not quite identical. It takes the env as a parameter so we need to figure out how to inject our header in there. rack-test - lib/rack/test.rb def post(uri, params = {}, env = {}, &block) env = env_for(uri, env.merge(:method => "POST", :params => params)) process_request(uri, env, &block) end Following the stack trace up we see the env passed into Rack::Test::Session.post comes from Capybara::RackTest::Browser and it turns out that env is computed in the Capybara::RackTest::Browser#env method. capybara - lib/capybara/rack_test/browser.rb def options driver.options end def env env = {} begin env["HTTP_REFERER"] = last_request.url rescue Rack::Test::Error # no request yet end env.merge!(options[:headers]) if options[:headers] env end The key is in the line env.merge!(options[:headers]) if options[:headers] and those options are delegated to the driver. Now we know how to inject our IP address onto the driver’s options. features/step_definitions/authentication_steps.rb Given /^I am connecting from ip "([^"]*)"$/ do |ip_address| page.driver.options[:headers] = {'REMOTE_ADDR' => ip_address} end Putting it all together we can write all our steps features/step_definitions/authentication_steps.rb Given /^I am connecting from ip "([^"]*)"$/ do |ip_address| page.driver.options[:headers] = {'REMOTE_ADDR' => ip_address} end Given /^I am connecting from ip "([^"]*)" behind a proxy$/ do |ip_address| page.driver.options[:headers] = {'X-Forwarded-For' => ip_address} end When /^I log in as "([^"]*)" with password "([^"]*)"$/ do |name, password| visit(new_session_path) fill_in('User name', :with => name) fill_in('Password', :with => password) click_button('Log In') end Then /^I should be on the home page$/ do URI.parse(current_url).path.should == root_path end Then /^authentication should have failed$/ do page.text.should include 'Unable to authenticate. Please try again' end Now the scenarios we wrote before all pass. To sum up capybara handles form submission superbly with fill_in('User name', :with => name) click_button('Log In') we can set any HTTP header in capybara with page.driver.options[:headers] = {'REMOTE_ADDR' => ip_address} Testing is good Since we’re testing the IP logic at both the unit level with RSpec and integration level with Cucumber and Capybara we can be pretty sure it’s all going to work correctly.

Programming With Kids

over 5 years ago | Alex Rothenberg: Alex Rothenberg

I’ve started to teach my kids to program. I figured I build websites professionally and it’d be a fun way for me to share what I do and help supplement their learning. And it was something they expressed interest in not something I was pushing. I suggested we build our own small version of facebook or twitter. Very quickly I learned two truths websites are boring games are fun Okay. I’ve never built a game before after a little digging there are plenty of tools in the open source world and many built on Ruby. We’re currently experimenting with three different tools/technologies. Shoes I first came across Shoes several years ago and was blown away. It was originally written by why and is now maintained by Team Shoes on github. “Shoes is the best little DSL for cross-platform GUI programming there is. It feels like real Ruby, rather than just another C++ library wrapper” Writing a Shoes app feels just like writing a Ruby app (it is Ruby!). The best analogy I can use is that what Rails does for websites, Shoes does for GUI apps. If you want to create a blue rectangle on a page, here’s your app Shoes.app do fill blue rect :top => 25, :left => 50, :height => 75, :width => 150 end A blue rectangle We can make it a bit more interactive and allow the user to move our rectangle around with the arrow keys and display the current coordinates Shoes.app do fill blue @player = rect :top => 25, :left => 50, :height => 75, :width => 150 @current_coordinates = para "(#{@player.left}, #{@player.top})" keypress do |key| @player.left += 10 if key == :right @player.left -= 10 if key == :left @player.top += 10 if key == :down @player.top -= 10 if key == :up @current_coordinates.replace "(#{@player.left}, #{@player.top})" end end The Blue Rectangle Moves We’re not limited to blue rectangles. We can replace it with an image Shoes.app do @player = image 'images/Starfighter.png', :top => 25, :left => 50 @current_coordinates = para "(#{@player.left}, #{@player.top})" keypress do |key| @player.left += 10 if key == :right @player.left -= 10 if key == :left @player.top += 10 if key == :down @player.top -= 10 if key == :up @current_coordinates.replace "(#{@player.left}, #{@player.top})" end end The Player is a Starship We’re writing Ruby in a fairly natural way. Shoes just gives us GUI methods like rect to create a rectangle or para to create a paragraph. Because this is Ruby, as your Shoes app gets more complex you can create classes and methods to organize and keep it manageable just as you would in any other app. There are all sorts of great resources out there including The Shoes Manual which includes a reference for all the elements you may use (like rect or para) why’s tutorial - the original introduction to Shoes sample apps - there are some really good ones here! Teaching Ruby to High School Girls (using Shoes) article by Sarah Mei Gosu Gosu is a gaming library so while Shoes lets us build any sort of GUI apps this is seemed like it might be a better fit since we’re interested in gaming. Luckily there’s a gem that wraps up the Ruby interface (Gosu can be used from C++ or Ruby). gem install gosu If we want to build a similar game to what we did in Shoes with a play we move around via the arrow keys we need to subclass the Gosu::Window class. require 'rubygems' require 'gosu' class Player def initialize(window) @image = Gosu::Image.new(window, "media/Starfighter.png", false) @x, @y = 125, 50 @angle = 0.0 end def draw @image.draw_rot(@x, @y, 0, @angle) end end class GameWindow < Gosu::Window def initialize super(640, 480, false) self.caption = "Gosu Tutorial Game" @player = Player.new(self) end def draw @player.draw end end window = GameWindow.new window.show And we see a window with a player that looks like a starship Starship player Its not too hard to make it move by overriding the update method in our window class require 'rubygems' require 'gosu' class Player attr_accessor :x, :y def initialize(window) @image = Gosu::Image.new(window, "media/Starfighter.bmp", false) @x, @y = 75, 50 @angle = 0.0 end def draw @image.draw_rot(@x, @y, 0, @angle) end end class GameWindow < Gosu::Window def initialize super(400, 300, false) self.caption = "Our Game" @player = Player.new(self) @current_coordinates = Gosu::Font.new(self, Gosu::default_font_name, 20) end def update @player.x -= 10 if button_down? Gosu::KbLeft @player.x += 10 if button_down? Gosu::KbRight @player.y += 10 if button_down? Gosu::KbDown @player.y -= 10 if button_down? Gosu::KbUp end def draw @player.draw @current_coordinates.draw("(#{@player.x}, #{@player.y})", 10, 10, 0, 1.0, 1.0, 0xffffff00) end end window = GameWindow.new window.show Starship player moves This example can be extended into a full Asteroids like like game where your ship has inertia. You should look at the source or an explanation on the gosu site. There are all sorts of great resources out there including Samples from the Gosu Showcase or Falling Blocks or CptnRuby Falling Blocks (tetris)   Captain Ruby Chingu an extension that seems to let us avoid re-writing common tasks Robot Chipmunk a physics library that makes it easy to do things like collision detection, gravity, etc Gravity and Collisions demo Even though we’re still writing Ruby, Gosu feels more like C++ Windows development I used to do long long time ago. I’m not sure if that’s inevitable and need to keep using Gosu to find out. gamesalad The last framework we’ve been working with is pretty different. GameSalad advertises it lets you “Create games for iPhone, iPad, Android, Mac, and HTML5. No coding required.” It follows a model similar to what Adobe Flash uses where you have Scenes containing Actors. You write your programs in a visual editor by dragging and dropping Actors onto Scenes, Rules onto Actors and Behavior onto Rules. For instance if we have a starship actor and we drop these rules onto it Starfighter rules We will get our familiar spaceship that can move left and right Starfighter Moving GameSalad is the least familiar to me but seems to be easiest for my kids to start working on. Not having to write any “code” or “do programming” makes it much easier to get started. It also can create iPhone or iPad games and I would never dream of exposing my kids to Objective-C. What’s next? We’ve started experimenting with all three of these tools and so far are having fun with all three. Hopefully we’ll figure out what works for us and perhaps try to write about it again in a few months. After writing this I came across a recent NY Times article Programming for Children, Minus Cryptic Syntax and Scratch also sounds interesting so I may have to look into that sometime too.

Twitter is the new RSS Reader

over 5 years ago | Alex Rothenberg: Alex Rothenberg

In 2008 I thought RSS was an awesome way to stay abreast of what’s going on, but now its 2011 and I find myself using Twitter more often than Google Reader to find new and interesting articles people have written. Readers tweet and retweet articles they find interesting which seems a lower barrier than leaving an “I like this” comment. As an author Twitter also gives you some idea of who is reading your posts and a way to connect with them. Back in 2008 I created a blog aggregator site http://waywework.it to group the all the people I work with and promote others to share their thoughts. I was so excited I even wrote an article about it. Now that its 2011, I’ve been asking myself how could I update http://waywework.it for the twitter world of today? I decide that if we’re going to follow people on twitter that’s what my site should facilitate. When new posts come in it should tweet them letting you see them if you follow @WayWeWorkIT. Enabling API access to twitter Once I had this I added the twitter gem to my application. I have to give a shout out John Nunemaker for writing this fantastic gem which made my task so simple. In the Gemfile gem 'twitter' I created a new twitter account @WayWeWorkIT and registered an application at https://dev.twitter.com/apps so I had my OAuth and access tokens. The only trick was I had to go Application Settings tab and configure it for Read and Write access then regenerate the tokens. Now that I had the keys and tokens from twitter I had to tell my application to use them without hardcoding them in my code. This took two steps. First, configuring the app to read the tokens from the environment in config/initializers/twitter.rb. Yes I am somewhat paranoid about accidentally tweeting from development but that if Rails.env.production? should save me. if Rails.env.production? Twitter.configure do |config| config.consumer_key = ENV['TWITTER_CONSUMER_KEY'] config.consumer_secret = ENV['TWITTER_CONSUMER_SECRET'] config.oauth_token = ENV['TWITTER_OAUTH_TOKEN'] config.oauth_token_secret = ENV['TWITTER_OAUTH_TOKEN_SECRET'] end end Secondly, setting the tokens on the heroku environment (I typed the real tokens instead of the XXXXXXXX’s). $ heroku config:add TWITTER_CONSUMER_KEY=XXXXXXXX $ heroku config:add TWITTER_CONSUMER_SECRET=XXXXXXXX $ heroku config:add TWITTER_OAUTH_TOKEN=XXXXXXXX $ heroku config:add TWITTER_OAUTH_TOKEN_SECRET=XXXXXXXX We can test it out (after deploying with git push heroku) $ heroku console >> Twitter.tweet('http://waywework.it aggregates blog articles') => # some big object returned >> Twitter.user_timeline('wayweworkit').first.text => "http://t.co/FCmUQdc3 aggregates blog articles" Great we just tweeted our first tweet for the world to see. Updating WayWeWork.IT to tweet new posts The app periodically scans the rss feeds it tracks and when it sees a new post it creates it in the app’s database. First we add a twitter_username to each feed we’re tracking class AddTwitterUsernameToFeeds < ActiveRecord::Migration def change add_column :feeds, :twitter_username, :string end end Then, add an after_create callback to tweet each time we create a new post. class Post < ActiveRecord::Base after_create :tweet delegate :twitter_username, :to => :feed def twitter_username_with_at_sign "@#{feed_twitter_username || 'WayWeWorkIT'} end # See https://dev.twitter.com/docs/tco-link-wrapper/faq#Will_t.co-wrapped_links_always_be_the_same_length # We should query instead of hardcoding 20 def short_url_length 20 end def tweet if Rails.env.production? non_title_part_of_tweet = " #{'x'*short_url_length} via #{twitter_username_with_at_sign}" max_title_length = 140 - non_title_part_of_tweet.length tweet = "#{title.truncate(max_title_length)} #{url} via #{twitter_username_with_at_sign}" Twitter.update(tweet) end end end Again with the “if Rails.env.production?” paranoia? You do know that you can never be too paranoid :) With the twitter gem its one line to tweet Twitter.update(tweet). The rest of it is to shorten the title so twitter’s 140 character limit wont cut off the url or the author’s name. Once this is in we’ll start seeing tweets like Using BDD and the email_spec gem to implement Email www.alexrothenberg.com/2011/10/31/usi… via @alexrothenberg Twitter is the new RSS Reader http://www.alexrothenberg.com/2011/11/07/twitter-is-the-new-rss-reader.html via @alexrothenberg Go ahead and follow @WayWeWorkIT on twitter and you’ll start seeing these blog posts.

Using BDD and the email_spec gem to implement Email

over 5 years ago | Alex Rothenberg: Alex Rothenberg

When implementing email functionality, the email_spec gem is something I’ve decided I can’t live without. It makes it so easy to write RSpec specs and Cucumber features around your email that you have no excuse not to. Today I’m going to go through an example how I recently used BDD to send an email in an app I was working on. When I think about email and my Rails environments this is how I typically want them to behave. test should not send emails and allow us to write specs or features against them development should not send emails but provide a UI to view what would be sent on localhost staging should not send emails but provide a UI to view what would be sent on a server production should send real emails to real people Last week I wrote about using letter opener to View Sent Email on a Server (without actually sending anything) describing how the letter_opener gem helps us in the development and staging environments. This article focuses on using email_spec gem in the test environment. Our Sample Project Let’s imagine we are working on a new startup in stealth mode. We want to generate buzz and prepare for a beta launch. We’re hiding the fact its all vaporware with a splashy homepage where people can request an invitation to the beta and records their email in our database. This is the same example as my article last week and there’s a live demo at http://awesome-site-staging.heroku.com/. What we’ll do today is not just record the email address but also send a “thanks for your interest” email to the user. We’re going to do this in BDD fashion bouncing back and forth between Cucumber Scenarios and RSpec Unit Tests Writing a cucumber scenario While the scenario fails Write a failing rspec spec Write code to make it pass The Cucumber scenario tells us what should be accomplished and when it fails it we use that to tell us what unit test we should write. Adding the email_spec gem We add it to our Gemfile group :test do gem 'email_spec' end We bundle and use the email_spec generator to let it initialize itself. $ bundle $ rails g email_spec:steps There’s also a manual step to get cucumber to load the email_spec gem. We need to create a file features/support/email_spec.rb require 'email_spec/cucumber' Our first Cucumber Scenario We know that when a user requests an invitation they should get an email so we write that requirement as a Cucumber Scenario. features/request_an_invitation.feature Feature: Build excitement for this vaporware In order to drum up interest As a user I will receive an exciting email when I request an invitation Scenario: Someone requests an invitation and receives an email Given I am on the home page When I request an invitation for "gullible@lemmings.com" Then "gullible@lemmings.com" should receive 1 email And they open the email And they should see the email delivered from "alex@awesome-startup.com" And they should see "Invitation request for Awesome New Startup received" in the email subject And they should see "Dear gullible@lemmings.com," in the email text part body And they should see "We have received your request " in the email text part body And they should see "Please check back at http://awesome-site-staging.heroku.com" in the email text part body We run it and it tells us we have a couple of missing steps. 1 scenario (1 undefined) 9 steps (7 skipped, 2 undefined) 0m0.006s You can implement step definitions for undefined steps with these snippets: Given /^I am on the home page$/ do pending # express the regexp above with the code you wish you had end When /^I request an invitation for "([^"]*)"$/ do |arg1| pending # express the regexp above with the code you wish you had end Oh right, the training wheels came off in cucumber-rails v1.1.1 and we don’t have web_steps.rb anymore. Let’s write these steps using capybara in features/step_definitions/invite_steps.rb Given /^I am on the home page$/ do visit root_path end When /^I request an invitation for "([^"]*)"$/ do |email| visit root_path fill_in 'email', :with => email click_button 'Request Invitation' end We run one more time and get a failure we expect. Its telling us we haven’t written any code to implement the scenario yet! Then "gullible@lemmings.com" should receive 1 email expected: 1 got: 0 (using ==) (RSpec::Expectations::ExpectationNotMetError) ./features/step_definitions/email_steps.rb:52:in `/^(?:I|they|"([^"]*?)") should receive (an|no|\d+) emails?$/' features/request_an_invitation.feature:9:in `Then "gullible@lemmings.com" should receive 1 email' Dropping into RSpec unit tests Our failing feature tells us what we need to implement so we drop down to the unit test level and start implementing it with TDD. The feature tells us an email should be be generated so let’s go. We’ll add to our invites_controller_spec specifying that it should create and deliver an InviteMailer. spec/controllers/invites_controller_spec.rb require 'spec_helper' describe InvitesController do describe 'PUT #update' do let(:invite) { mock(:email => 'someone@someco.com', :save => true) } let(:invite_mailer) { mock } before do InviteMailer.should_receive(:invite_requested).with(invite).and_return(invite_mailer) invite_mailer.should_receive(:deliver) Invite.should_receive(:new).with('email' => 'someone@someco.com').and_return(invite) post :create, :invite => { :email => 'someone@someco.com' } end it { should redirect_to root_url } it { should set_the_flash.to("Thanks for your interest someone@someco.com. You will hear from us soon.") } end end Of course we get an error uninitialized constant InviteMailer. We fix that by creating the mailer (it doesn’t do anything yet) app/mailers/invite_mailer.rb class InviteMailer < ActionMailer::Base end The error changes Failure/Error: InviteMailer.should_receive(:invite_requested).with(invite).and_return(invite_mailer) (<InviteMailer (class)>).invite_requested(#<RSpec::Mocks::Mock:0x82c96210 @name=nil>) expected: 1 time received: 0 times We add the code to our controller to create and deliver the email in app/controllers/invites_controller.rb class InvitesController < ApplicationController def create @invite = Invite.new(params[:invite]) if @invite.save InviteMailer.invite_requested(@invite).deliver redirect_to root_path, :notice => "Thanks for your interest #{@invite.email}. You will hear from us soon." else render :action => "new" end end end Are we done? Checking the Cucumber Scenario… The RSpec unit tests pass now but the Cucumber features are still failing. When I request an invitation for "gullible@lemmings.com" # features/step_definitions/invite_steps.rb:5 undefined method `invite_requested' for InviteMailer:Class (NoMethodError) ./app/controllers/invites_controller.rb:10:in `create' (eval):2:in `send' (eval):2:in `click_button' ./features/step_definitions/invite_steps.rb:8:in `/^I request an invitation for "([^"]*)"$/' features/request_an_invitation.feature:8:in `When I request an invitation for "gullible@lemmings.com"' Duh our InviteMailer doesn’t do anything. Back down to the unit tests We write our spec/mailers/invite_mailer_spec.rb. We need to include some EmailSpec modules so we have access to its matchers. require 'spec_helper' describe InviteMailer do include EmailSpec::Helpers include EmailSpec::Matchers describe '.invite_requested' do let(:invite) { Factory.build :invite, :email => 'someone@someco.com' } describe 'one email to one user' do subject { InviteMailer.invite_requested(invite) } it { should deliver_to invite.email } it { should deliver_from 'alex@awesome-startup.com' } it { should have_subject "Invitation request for Awesome New Startup received" } it { should have_body_text "Dear someone@someco.com," } it { should have_body_text "We have received your request" } it { should have_body_text "Please check back at http://awesome-site-staging.heroku.com" } end end end Of course it fails because we still haven’t implemented anything. Let’s add some code to app/mailers/invite_mailer.rb class InviteMailer < ActionMailer::Base def invite_requested(invite) @invite = invite mail :to => invite.email, :from => 'alex@awesome-startup.com', :subject => 'Invitation request for Awesome New Startup received' end end and we can use haml to format the body in app/views/invite_mailer/invite_requested.text.haml == Dear #{@invite.email}, We have received your request to be invited into our awesome site. We'll let you know as soon as its available. Please check back at http://awesome-site-staging.heroku.com You must be very excited! Thanks An Awesome New Startup We run the rake one more time and … We’re Done Everything passes - the specs and the features! $ rake ruby -S rspec <a long list of _spec.rb files> ............ Finished in 2.64 seconds 12 examples, 0 failures ruby -S bundle exec cucumber --profile default Using the default profile... Feature: Build excitement for this vaporware In order to drum up interest As a user I will receive an exciting email Scenario: Someone requests an invitation and receives an email Given I am on the home page When I request an invitation for "gullible@lemmings.com" Then "gullible@lemmings.com" should receive 1 email And they open the email And they should see the email delivered from "alex@awesome-startup.com" And they should see "Invitation request for Awesome New Startup received" in the email subject And they should see "Dear gullible@lemmings.com," in the email body And they should see "We have received your request" in the email body And they should see "Please check back at http://awesome-site-staging.heroku.com" in the email body 1 scenario (1 passed) 9 steps (9 passed) 0m0.293s I hope you’ll consider using the email_spec gem and BDD the next time you have to add email to your app.

Using Letter Opener to View Sent Email on a Server (without actually sending anything)

over 5 years ago | Alex Rothenberg: Alex Rothenberg

When developing email functionality you don’t want to send real emails to real people before in production. At the same time you need to send them to ensure they are formatted correctly and contain the proper information. You can (and should) write integration tests to verify this but that helps developers gain confidence, what can we do to show non-technical stakeholders that it all works? Today I’m going to show you how to use Ryan Bates’ letter_opener gem to let you preview your emails without actually sending them. Ryan of course does the always awesome RailsCasts. Let’s think about the different Rails environments and how we want them to behave with email. test should not send emails and allow us to write specs or features against them development should not send emails but provide a UI to view what would be sent staging should not send emails but provide a UI to view what would be sent production should send real emails to real people Looking at this, Rails works really well for test with ActionMailer’s :test delivery method that stores the emails in the ActionMailer::Base.deliveries array so you can then use email_spec to write your specs. Production is also covered as long as you give it your mail server configuration. That leaves development and staging which look identical but we’ll see that they are slightly different. I’ll spend the rest of this article talking about how letter_opener lets us do what we want in these environments. An example Let’s imagine we are working on a new startup in stealth mode. We want to generate buzz and prepare for a beta launch. We’re hiding the fact its all vaporware with a splashy homepage where people can request an invitation to the beta and it sends a “thanks for your interest” email. Lastly, we want to test it in development and staging. Here’s a live demo at http://awesome-site-staging.heroku.com/ if you want to dive in and start clicking. After you request an invitation it shows a page like this Vaporware Homepage Logfile testing (we can do better) When you fill in your email and click the Request Invitation button, our controller uses a mailer to create and deliver the email. class InvitesController < ApplicationController def create @invite = Invite.new(params[:invite]) @invite.save InviteMailer.invite_requested(@invite).deliver redirect_to root_path, :notice => "Thanks for your interest #{@invite.email}. You will hear from us soon." end end The only way to tell whether the email worked is to scroll through the development.log until you see something like this Sent mail to alex@alexrothenberg.com (20ms) Date: Fri, 21 Oct 2011 15:09:16 -0400 From: admin@newstartup.com To: alex@alexrothenberg.com Message-ID: <4ea1c35cc3d5b_6693830916bc43754@Alex-Rothenbergs-MacBook-Pro.local.mail> Subject: Invite requested ... We have received your request to be invited into our awesome site. We'll let you know as soon as its available. Please check back at http://awesome-site.heroku.com You must be very excited! Thanks An Awesome New Startup Ok if you’re a developer and you enjoy reading log files but letter_opener lets us do better. Using letter_opener in development Letter_opener provides us with a UI so we can view the emails right in our browser. It’s super easy to add this gem and I’ll just copy the instructions from its README Preview email in the browser instead of sending it. This means you do not need to set up email delivery in your development environment, and you no longer need to worry about accidentally sending a test email to someone else’s address Rails Setup First add the gem to your development environment and run the bundle command to install it. gem "letter_opener", :group => :development Then set the delivery method in config/environments/development.rb config.action_mailer.delivery_method = :letter_opener Now any email will pop up in your browser instead of being sent. The messages are stored in tmp/letter_opener. Once we’ve done that what happens when we use the site to request an invitation? A new tab opens up with the email right there. Now as a user we can tell it’s correct and any non-technical people on the team can feel their confidence rise. Previewing an Email with Letter Opener in Development How does letter_opener actually work? Rails goes through the standard flow to create the mail object and when it’s ready to deliver the message it calls letter_opener’s deliver! method because we registered letter_opener as the action_mailer.delivery_method. Letter_opener saves the email to your file system as an html file then uses launchy to open it in a browser using the file:// protocol. There will be a couple of problems once we move onto a server which brings us to staging. Using letter_opener on staging If you’re like me you probably have a staging environment where you or your stakeholders can validate your app before releasing it to production and your end users. There are two aspects of this environment that wont work with letter_opener the way it did in development We need to use http:// not file:// to preview the emails because the browser is not on the same file system where the emails are written We may not be able to write to the file system. For example if we have deployed to heroku. I had to make some changes to letter_opener to support this kind of server environment. The fork is available at https://github.com/alexrothenberg/letter_opener/tree/on_a_server and I’ll update the article if my pull requests are merged back in. We need to make a few changes to our application. 1 - Update our Gemfile to use the fork from github gem 'letter_opener', :git => "git://github.com/alexrothenberg/letter_opener.git", :branch => "on_a_server" 2 - Add a debugging UI link so users can get to the “preview emails” page in something like layouts/application.html.haml = link_to 'Preview Emails', letter_opener_letters_path if Rails.env.staging? 3 - If you cannot write to the filesystem let letter_opener know in your config/environments/staging.rb config.action_mailer.delivery_method = :letter_opener LetterOpener.cannot_write_to_file_system! Now we can see it all in action. First, we request an invite. Previewing an Email with Letter Opener in Development Then, we click the link “view the Emails that users would have received” link at the bottom and see an “inbox” of everything the app sent. Previewing an Email with Letter Opener in Development Fincally clicking one message lets us preview it just as we did in devellopment Previewing an Email with Letter Opener in Development We are able to run on heroku without writing to the file system by using the FakeFS gem which simulates the filesystem in memory. FakeFS is designed to be used for testing and one caveat to be aware of is that your old emails will disappear if heroku recycles your dyno due to inactivity. I hope you think letter_opener is useful and give it a try the next time you need to send email. Remember here’s a live demo at http://awesome-site-staging.heroku.com/ of the site we’ve been talking about here.

Chaining ActiveRecord Scopes from Different Models

over 5 years ago | Alex Rothenberg: Alex Rothenberg

You probably know you can chain ActiveRecord scopes together and it combines it all together into one sql statement, but did you know that you can also use scopes from associated models in your chain? Let me show you with an example. Let’s say we have a discussion site where users can post comments with two simple models: class User < ActiveRecord::Base has_many :comments end class Comment < ActiveRecord::Base belongs_to :user end We could display a list of all users with User.all or even display them alphabetically with User.order(:name) (yes I’d create a scope if I were doing this for real). What if I wanted to display the users sorted so that the ones with the most recent comment was first? User.includes(:comments).merge(Comment.order('comments.created_at desc')) There’s a lot going on there, let’s break it down. User.includes(:comments) - tells active record to query both the users and comments tables Comment.order('comments.created_at desc') - sorts the results by the date of the comment (we need to specify the table and column name since created_at is also a column on the users table) merge(Comment.XXX) - lets us use a scope from the Comment model even though we’re dealing with Users When ActiveRecord and ActiveRelation take all this and convert it into a sql statement it will join the users and comments tables and order by the comments.created_at column. Here’s the sql I actually get in irb (boy am I glad I didn’t have to type that sql myself!). > User.includes(:comments).merge(Comment.order('comments.created_at desc')) SQL (0.4ms) SELECT "users"."id" AS t0_r0, "users"."name" AS t0_r1, "users"."created_at" AS t0_r2, "users"."updated_at" AS t0_r3, "comments"."id" AS t1_r0, "comments"."user_id" AS t1_r1, "comments"."body" AS t1_r2, "comments"."created_at" AS t1_r3, "comments"."updated_at" AS t1_r4 FROM "users" LEFT OUTER JOIN "comments" ON "comments"."user_id" = "users"."id" ORDER BY comments.created_at desc Adding Scopes to make it usable It works to type all that but in a real application you’d add scopes to make it easier to work with. Let’s do that! class User < ActiveRecord::Base has_many :comments scope :by_most_recent_comment, includes(:comments).merge(Comment.most_recent_first) scope :with_recent_comments, includes(:comments).merge(Comment.recently(1.month.ago)) end class Comment < ActiveRecord::Base belongs_to :user scope :most_recent_first, order('comments.created_at desc') scope :recently, lambda { |date| where('comments.created_at >= ?', date) } end Now we can write some nice simple scopes like User.by_most_recent_comment to get all users sorted so the ones with recent comments are at the top User.with_recent_comments to get all users who have commented in the past month User.with_recent_comments.by_most_recent_comment to get users who have commented in the past month sorted by the date of their most recent comment. Happy scoping!