I’ve been using a pattern for loading javascript for specific pages that I would like to share. I have been using it for the past three years across many projects, and has proven to be durable.

It was created in response to three patterns that I saw and disliked.

  • Using javascript_include_tag to bring in page specific javascript
  • Keying javascript off of a html element id if ($("#some_div")) { ... }
  • Inline javascript

I found all these solutions to be inadequate because they required extra web requests, didn’t take advantage of js compression, had javascript overhead of checking the page for contents, didn’t allow the use of coffeescript, or left javascript scattered around the project. The Rails Asset Pipeline solves all those problems.

My solution is to use a JavaScript object to wrap pages, which I will call Page Objects.

A Page Object looks like this:

app/assets/javascripts/app/pages/home_page.js.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
window.APP.HomePage = class HomePage
  constructor: (options) ->
    @data = options["data"]

  bind: ->
    @bindThing()
    @bindOtherthing()

  bindThing: ->
    otherSomething(@data)

  bindOtherthing: ->
    otherSomething()

Every Page Object is applied to window.APP, has a bind method which will run any page specific code, and lives in app/assets/javascripts/app/pages. You will see why in a moment. The constructor is optional.

We bring this into our asset pipeline like so:

app/assets/javascripts/application.js
1
2
3
//= require ./app/init
//= require_tree ./app/objects
//= require_tree ./app/pages

Our pages are assigned to window.APP, which needs to be initialized before the page objects are loaded. Because requiring javascript files must happen at the top of your file, before any executable javascript is written, we must move the initialization of window.APP to another file.

app/assets/javascripts/app/init.js
1
window.APP = {}

Now, we want to have rails instantiate one of these objects, and call our bind method for us.

app/helpers/application_helper.rb
1
2
3
4
5
6
7
module ApplicationHelper
  def load_javascript_class(javascript_class, options = nil)
    content_for :page_javascript do
      javascript_tag "$(function(){ (new window.APP.#{javascript_class}(#{options.to_json})).bind(); })"
    end
  end
end
app/views/layouts/application.html.haml
1
2
3
4
5
6
7
!!!5
%html{lang: "en"}
  %body
    = render 'layouts/header'
    = yield
    = render 'layouts/footer'
    = yield :page_javascript

The last part of it is to call it from your view

app/views/home/index.html.haml
1
2
3
4
5
- load_javascript_class "HomePage", data: ["foo", "bar"]

.container
  .row
    %h3 List:

With this pattern, you can have page specific javascript while utilizing the asset pipeline of rails. This solution also solves the problem of how to get data from rails to your javascript. You can see in the helper that if you pass in a second argument to load_javascript_class that it will take it, and turn it into json for your page object’s constructor.

You may have noticed that I also have a app/objects required in the application.js. I do this to create objects that may be shared between pages. I tend to use a similar pattern as page objects, and instantiate/delegate to them from a page object.

Some sites need to have two sets of javascript, perhaps for very different sections of the site, like an admin area. You can change the helper to be

app/helpers/application_helper.rb
1
2
3
4
5
def load_javascript_class(namespace, javascript_class, options = nil)
  content_for :page_javascript do
    javascript_tag "$(function(){ (new window.#{namespace.to_s.upcase}.#{javascript_class}(#{options.to_json})).bind(); })"
  end
end

The first parameter is now where on window to look for your objects. Perhaps you add a line in init.js for window.ADMIN = {} and then load objects from there with load_javascript_class :admin, "SomePage". This pattern should be flexible from there.

This pattern has solved most my issues for the past few years. I am sure there is a different pattern to use for projects with turbolinks, but I will continue to bring this pattern into all other projects because of the utility it provides.

Back in March, the company I work for was creating a small app and were trying to decide which javascript frame work to use. There was an email chain debating which framework to use. I finally responded, and today a coworker convinced me to post that email:


Was debating if I wanted to take the bait, but I love to argue, so I couldn’t resist.

I am not a fan of pushing the entire rendering process to the client. I am also no longer a fan of client side routing (hash nor push state). It isn’t about CPU power, and browser capabilities. I’ve used the first six frameworks in todomvc.com and a couple of the others, and the way I grade them is by their testability, maintainability, and productivity. Also to say, I am a big fan of modularization, which can be interpreted as numerous small single purpose apps.

My opinions on the big 4 frameworks:

Backbone

I love backbone. So easy to get started. So easy to do whatever I want. However, I have a hard time believing that it can be scaled to a team size without some hard core discipline, and structure.

Backbone models and collections are freaking awesome, out of all client side frameworks I have dealt with, dealing with data is absolutely the easiest in Backbone. However, it is quickly negated by its shitty controllers/routers/ViewModel layer (if you haven’t heard of a ViewModel, I think you should look up the MVVM - model view view/mode pattern). Backbone intentionally leaves this to you. I’ve browsed a lot of random open source projects on github that use backbone and everywhere I look there is a different way to organize things, and it feels chaotic. If you value the same things about code as I do, that is testability, modularity, readability, etc, you have to come up with your own scheme that hopefully fits all your needs. Backbone’s intentional shortcomings are picked up by some frameworks that are built on top of it, like Marionnette… but man I hate frameworks on frameworks.

Finally the view. Not the view you know of from rails, I’ll call that the template. The view object. I don’t mind how they bind data or events, but ugh, the lack of templating kills me. You have to compile your own template (not a big deal, jquery and underscore provide decent templating functions), and inject that into DOM via some helper methods (Urghhh). So if you have a collection, and render a list, then behind the scenes modify a model/the collection, you have to go delete your own element and replace it in the right spot. I found it manageable until I rendered a form, and tried to modify the same view with some view changes, and it became hell.

Angular

My first attempts at angular were thwarted by horrific documentation, and my second attempt was painful because they were in progress of updating their horrific documentation to actually document the version they released. Oh and (at the time) an incredibly intimidating dependency injection strategy. They have matured and now the documentation isn’t completely rubbish and the dependency injection thing actually makes sense. I am currently using angular for my side project.

Angular is painfully verbose. They provide a dependency injection framework that has you declaring random variables everywhere with eye blistering $ signs (I guess that is because I usually use coffeescript these days). However, I am a big fan of DI, and out of all the frameworks, I believe Angular is the only one that really tries to solve such a problem.

Another awesome thing about angular is it is designed to be able to be tested from the ground up. Even with the angular documentation was shit, I gave angular those attempts because they actually tested their own code with a massive test suite, and showed you how to use it, and it looked half decent. You will be surprised how many projects in the javascript community (well, any open source community really) that become popular don’t even have a unit test suite, or a really pointless shitty one (cough meteor cough). Part of being testable is being modular, and angular skews that axis very high.

Angular provides no model layer… it lets you use any plain old javascript object. A freedom, but given that is was so opinionated every where else (or rather, provided structure every where else), this is a let down.

My last point is the way that angular binds its data. This has been an internal battle for me for quite some time; data and event binding via pseudo html attributes vs declared event observers and interpolation. They are very different styles. I wouldn’t necessarily choose a framework because of how they bind events, but there are some tradeoffs that I have seen some highly philosophical and argumentative developers will fight over, but I’m not going to get into that here.

Ember

Now that ember has successfully separated its image from sprout, I think ember is very solid. Solid models/events, solid and high profile team behind it, solid (IMHO) way to declare templates, sensible view models, not bad collections. The only thing keeping me from constantly using ember js is its tight integration with handlebars (my use case for these frameworks don’t align with that kind of templating, I’ll explain in a sec).

Knockout

Last time I tried knockout, it felt like they were cramming ajax down my throat… they seem much better about that now. It has an awkward and sometimes ridiculously verbose ways of doing things. Was built by microsoft, the inventors of MVVM… was built by microsoft so I don’t give it a serious look.

Here are some random thoughts:

I’m done with client side routing for a while, it is annoying to deal with. You have to intercept all links, and redirect it back to your own router. You have to make sure that if you fill out a form, go to another page, come back to the form that the form is emptied. If one page breaks you may have just made the user stuck without any kind of indication that they are used to. You have to basically reinvent http status codes. Github can’t even get it right (if you hit the back button too fast while browsing code, you can end up on a page different from what is in your url bar. This happens to me all the time and annoys the crap out of me.) With pushstate you have to make sure every page works if you hit the refresh button.

Rendering html has been solved before, and optimized. Think about all the compression web severs do, think about how browsers do progressive loading. Think about how in our ajax world we had to reinvent so many things (spinners, status codes, etc.)

On my current side project I chose angular. There is only one reason I chose it over the others, and that is because of how it binds data/events. I don’t know about you, but I love haml/jade. The way I like to work when I have a scenario where I have dynamic client views is to have the server do as much rendering as possible, and then provide a template for whatever needs to be dynamic. This means using haml/jade on the server, and then feeding that into the templating mechanism of my mvvm framework. The syntax of handlebars is not easily compatible with any whitespace based markup language. With angular I can have the server side compile jade, and leave in the data binding syntax of angular.

like this (jade):

p(class=") foo  #{baz}

If baz was a variable set to “qux” on the server, that would compile to

<p class=">foo  qux</p>

and then angular would pick those up later for templating.

This fits well with my two of my three favorite features in rails; forms and routes.

form_for is such a time saver in my opinion, and I miss rails routes every time I try something that isn’t rails. With this scheme in a rails environment, you get to use your form_for or your *_path methods on the server, then let the client do work after. I have gotten this to work before, I don’t remember exactly, but I believe you can trick rails into taking odd parameters into url helpers…

if this were my haml:

%p= post_path("")

and you had post declared as a resource, you would get

<p>/posts/</p>

which can be fed into a templating engine. I think you can do the same with form_for and stuff too.

However, my choices are for my personal side project, where I know where everything is… have to remember that different factors come into play when you are in a team.

K, I’m done rambling… I didn’t even get into testability, but whatever.


Fast forward to today. We use hamlc + Backbone.js + marionette, and jasmine. Looks like github finally fixed their back button problem. My url_for trick doesn’t work with certain characters in certain versions of rails. I learned that angular is very ugly when trying to deal with events over sockets due to the lack of the model. Backbone is painful with relational data (especially many to many).

Seems like I have a hard time being motivated enough to write anything down. There is definitely some overhead in writing my own blog, which is why I moved away from my custom Django blog. From there I have tried a bunch of static site generators powered by git/github (like nanoc, jekyll and webgen). I think switching to a tool that I don’t have to maintain and has features like mobile compatibility or email posting might tip me over the edge.

While trying to install Google v8, I had an error:

v8-read-only$ scons
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
g++ -o obj/release/api.o -c -Wall -Werror -W -Wno-unused-parameter -Wnon-virtual-dtor -pedantic -m32 -O3 -fomit-frame-pointer -fdata-sections -ffunction-sections -ansi -fno-rtti -fno-exceptions -fvisibility=hidden -Wall -Werror -W -Wno-unused-parameter -Wnon-virtual-dtor -pedantic -m32 -O3 -fomit-frame-pointer -fdata-sections -ffunction-sections -ansi -DV8_TARGET_ARCH_IA32 -DENABLE_VMSTATE_TRACKING -DENABLE_LOGGING_AND_PROFILING -DENABLE_DEBUGGER_SUPPORT -Isrc src/api.cc
cc1plus: warnings being treated as errors
src/handles-inl.h: In static member function 'static void v8::V8::RemoveMessageListeners(void (*)(v8::Handle<v8::Message>, v8::Handle<v8::Value>))':
src/handles-inl.h:50: error: dereferencing pointer '<anonymous>' does break strict-aliasing rules
src/handles-inl.h:50: error: dereferencing pointer '<anonymous>' does break strict-aliasing rules
src/utils.h:739: note: initialized from here
cc1plus: error: dereferencing pointer 'dest' does break strict-aliasing rules
cc1plus: error: dereferencing pointer 'dest' does break strict-aliasing rules
cc1plus: error: dereferencing pointer 'dest' does break strict-aliasing rules
cc1plus: error: dereferencing pointer 'dest' does break strict-aliasing rules
src/api.cc:3767: note: initialized from here
scons: *** [obj/release/api.o] Error 1
scons: building terminated because of error

Solved by using export GCC_VERSION=44, before running scons.

I wrote a simple Javascript State Machine.

It is intended for keeping track of what the current state is for my heavy AJAX app at work.

I also learned a lot about OO in javascript without using jQuery or the prototype framework, by using prototypes. I wanted to do that so that it would be framework independent.

Below is a simple example of how I use the state machine, and shows a bit of how I connected it with Really Simple History

I have included in this example some comments to show my thinking throughout, and perhaps how to use it.

Site.prototype = new StateMachine();
Site.prototype.states = {
    Begin: {
        enter: function(){
            // do some animation
        },
        exit: function(){
            // hide some stuff
        }
    },
    Page: {
        enter: function(){
            // show some page
        },
        exit: function(){
            // hide it
        },
        change: function(page){
            // example of some event
            this.pages.change_page(page);
            // events can call events
            this.handleEvent('setURL');
        },
        setURL: function(){
            //example of how I integrate with really simple history
            dhtmlHistory.add(['pages'].concat(this.pages.current_page.split('/')).join('.').toLowerCase());
        }
    }
};

// These are some call backs I used for debugging with firebug to ensure
// that events were firing
Site.prototype.beforeEvent = function(name){
    console.log('begin event: ', name);
}
Site.prototype.afterEvent = function(name){
    console.log('end event: ', name);
}
Site.prototype.beforeStateChange = function(to, from){
    console.log('begin state change to: ', to, ' from: ', from);

    // as an example of intercepting, I can stop a state from changing by returning false
    if(to == 'Page' && this.pages.blocker == 'Page'){
        // some logic
        return false;
    }
    return true;
}
Site.prototype.afterStateChange = function(to, from){
    console.log('end state change to: ', to, ' from: ', from);
}

// The actual defenition. Instance vars can be set in it.
function Site(){
    this.pages = new Page();
}

// global scope, so that it can be accessed globally (as it wouldn't normally
// be because the scope that I actually instantiate it inside prorotype's window onload)
var Davis; 


// Once again, just an example of how I integrate it with Really Simple History
function historyChange(newLocation, historyData) {
    var hash = newLocation.split('.');
    var newState = hash.shift().capitalize();
    if(newState == '') newState = 'Begin';
    if(Davis.changeState(newState))
    {
        if(hash.length > 0) Davis.handleEvent('change', hash.join('/'));
    }
}

// This window observe for onload is prototype specific... But you can achieve the same other ways.
Event.observe(window, 'load', function() {
    Davis = new Site(); // my requirements need me to initialize after load

    // Really Simple History stuff
    dhtmlHistory.initialize(historyChange);
    historyChange(dhtmlHistory.currentLocation || '');
});

While implementing this, I also learned a bit about bookmarking and enabling the back button of ajax states. Really Simple History has worked ok for me, but it has some quirks… some of which I haven’t solved yet (especially in IE) and those bugs may be above.

I also got my first dose of unit testing in javascript… and found some really cool library to assist in the development called newjs . However, at the time of this writing, the unit tests are not up to the current code, as a lot has changed… I will deal with that later.

Anyway, while my implementation surely isn’t the best in the world, I hope someone can find use from it.

http://github.com/phillc/Javascript-State-Machine

I needed something to help me get through a multi-dimensional array. So I extended the Array class.

Grab expects an array of coordinates.

class Array
  def grab(position)
    value = self.fetch(position.first)
    value = value.grab(position[1..-1]) unless position[1..-1].empty?
    value
  rescue NoMethodError
    raise(IndexError, "Multi Dimensional Array not deep enough")
  end
end

Then I can do this:

>> [[1,2,3],"asdf",[[11,22,33],5,6,7]].grab([2,0,0])
=> 11
>> [[1,2,3],"asdf",[[11,22,33],5,6,7]].grab([2,0,2])
=> 33
>> [[1,2,3],"asdf",[[11,22,33],5,6,7]].grab([2,1])
=> 5
>> [[1,2,3],"asdf",[[11,22,33],5,6,7]].grab([1,0])
IndexError: Not an array.
    from /Users/phillip/Desktop/rworkspace/davisbrandcapital/lib/tagging.rb:73:in `grab'
   from (irb):64
>> [[1,2,3],"asdf",[[11,22,33],5,6,7]].grab([1])
=> "asdf"
>>

I had some Issues with cucumber/selenium working properly with authlogic. After much searching, I’ve figured out how to get it all to work properly.

I would get an error like:

When I follow "Manage pages"                          # features/step_definitions/webrat_steps.rb:19
  ed out after 5000ms (Selenium::CommandError)
  /opt/local/lib/ruby/1.8/timeout.rb:62:in `timeout'
  /opt/local/lib/ruby/1.8/timeout.rb:93:in `timeout'
  (eval):2:in `/^I follow "([^\"]*)"$/'
  features/plain/admin_page.feature:8:in `When I follow "Manage pages"'

Initially, to setup authlogic to work with regular webrat tests, I had to put the following in my env.rb:

require "authlogic/test_case"

Before do
  activate_authlogic
end

After getting it working with webrat, I decided I wanted to test some of my javascript and AJAX with selenium, so I followed this guide

The database_cleaner gem had to be added because you can’t use

Cucumber::Rails.use_transactional_fixtures

with selenium, so it had to be removed from the env.rb and placed in the plain.rb. As a result, this ended up in my enhanced.rb

require 'database_cleaner'
  Before do
    # truncate your tables here, since you can't use transactional fixtures*
    DatabaseCleaner.strategy = :truncation
    DatabaseCleaner.clean
  end

and this ended up in my plain.rb

require 'database_cleaner'
DatabaseCleaner.strategy = :truncation
DatabaseCleaner.clean

Originally, I had it just in my enhanced.rb as an After block instead of Before, but after further contemplation, I realized that if something goes terribly wrong with the selenium tests, then the database would have bad data in it… So might as well clean it before hand.

Finally, my problem with authlogic + seleniu, was how I wrote my test. The way it was erroring out made it look like something completely different (the selenium timeout error), but after I watched it a couple times closely, I determined that the test was being sent to the next page before the “button press” was executed.

Here is the beginning of my test that failed:

Scenario: Visit Add Page page
    Given I am logged in
    And I am on "the admin page"
    When I follow "Manage pages"
    And I follow "New Page"

With a little help from a post on stack overflow, I got it to work with the following:

def user
  @user ||= Factory.create(:user)
end

def login
  user
  fill_in "Email", :with => @user.email 
  fill_in "Password", :with => @user.password
  click_button "Login"

  # This is what was added
  if Webrat.configuration.mode == :selenium
    selenium.wait_for_page_to_load
  end
end

Given /^I am logged out$/ do
  @current_user_session.destroy if @current_user_session
end

Given /^I am logged in$/ do
  visit path_to("the login page")
  login
end

When /^I login$/ do
  login
end

Notice I had to add the if selenium line in order to get it to work in webrat.

Something tells me there is a better way to do it… probably overriding the click_button method when selenium is loaded… but I don’t know it well enough quite yet to venture that far, I’ll probably try it soon though.

Edit: oh, its a thing with webrat… but installing the newest version didn’t fix it for me, then I actually read the ticket… I’ll stick with my current solution for now.

Edit2: Actually the issue is in the visit method, if you can believe that. click_button works fine, as it waits for the page to load before clicking, but the visit method is sent so fast, that because of the way my test is set up, we are sent to the next page either before the login button is pressed, or before the request gets a chance to process… I don’t feel like investigating which one it exactly is, because the solution is the same… wait for the next page to load.

Was attempting to compile e-text editor on ubuntu 9.10 (yea yea, I know… my right to complain about broken packages disappears since its alpha) just to try it out, but had a sick number of errors ranging from “Cannot compile wxWidgets” to “Cannot compile WebKit”.

Finally, after trying multiple ways of compiling wxWidgets, I figured out the real error was

"./include/wx/gsocket.h:40: error: using typedef-name ‘GSocket’ after ‘class’"

So I applied a patch I found at http://trac.wxwidgets.org/ticket/10883 to the wxwidgets folder. and it suddenly worked.

edit: I turned out that I also had to update glib. glib version 2.20 did it for me.