Make "rake notes" learn about Haml, Sass, CoffeeScript, and other file types

Rails comes with a Rake task notes that shows code comments that start with "TODO", "FIXME", or "OPTIMIZE".

While it's generally not good practice to leave them in your code (your work is not done until it's done), in larger projects you will occasionally have to use them as other parts of the application that you depend upon are not yet available.
To keep track of them, run rake notes. Its output looks something like this:

$ rake notes
app/controllers/fron...

Using form models (aka decorators) with Devise

To use a form model with devise, you can simply override #resource_class in a controller. A typical use case would be the registrations controller, as users will need some fields only on sign-up. Example:

class Frontend::Authentication::RegistrationsController < Devise::RegistrationsController

  private

  def resource_class
    FrontendUser::AsSignUp # my decorator class, extending from FrontendUser
  end

end

Fontawesome 4 helper classes

Fontawesome 4 ships with many useful CSS helper classes.

Enlarge Icon

Add fa-lg (133%), fa-2x, fa-3x, fa-4x or fa-5x.

Fixed-width Icon

Add fa-fw. Will give all icons the same width.

Styling Lists

Add fa-ul to a <UL> and fa fa-<icon name> fa-li to a <LI> to give the list items custom "bullets".

Bordered Icon

Add fa-border to get a border around the icon.

Spinning Icon

Add fa-spin to make any icon rotate. Suggested icons: fa-spinner, fa-refresh, fa-cog. Doesn't work in IE <10.

Ro...

Rails 4 introduced collection_check_boxes

Starting from Rails 4.0, you can use a special form options helper called #collection_check_boxes. It behaves similar to #collection_select, but instead of a single select field it renders a checkbox and a label for each item in the collection.

= form_for @post do |form|
  = form.collection_check_boxes :author_ids, Author.all, :id, :name_with_initial

How generated form params look like
---------------------------------...

Thread-safe collections in Ruby

When using threads, you must make your code thread-safe. This can be done by either locking (mutexes) all data shared between threads, or by only using immutable data structures. Ruby core classes like String or Array are not immutable.

There are several gems providing thread-safe collection classes in Ruby.

concurrent-ruby

The concurrent-ruby gem provides thread-safe versions of Array and Hash:

sa = Concurrent::Array.new # supports standard Array.new forms
sh = Co...

Add an alternative image source for broken images

Awesome hack by Tim VanFosson:

<img src="some.jpg" onerror="this.src='alternative.jpg'" />

Differences between transactions and locking

Web applications can be used by multiple users at the same time. A typical application server like Passenger has multiple worker processes for a single app. In a distributed deployment setup like we use at makandra you will even have multiple application servers, each with their own worker pool.

This means that your code needs to deal with concurrent data access. The two main tools we use to cope with concurrency are database transactions and distributed locks. These two are not interchangeable. You ca...

Verifying doubles in RSpec 3

RSpec 3 has verifying doubles. This breed of mock objects check that any methods being stubbed are present on an instance of a given class. They also check methods aren't called with the wrong number of arguments.

This dual approach allows you to move very quickly and test components in isolation, while
giving you confidence that your doubles are not a complete fiction.

You should always prefer using a verifying double to using an old-school mock...

Communication between collaborating directives in Angular

What if a complicated component comes along that is naturally modeled by multiple directives? This group of directives, as a whole, form a single self contained component. None of directives in the group can stand alone because they only make sense when used together; they collaborate; they are aware of each other and need to communicate with each other.

This post will discuss best practices for managing communication among collaborating directives and illustrate these practices with an example.

How to enable WebGL in Chrome

Check your GPU state on chrome://gpu. If it reads "WebGL: Hardware accelerated" in the first list, you're set. Else:

  1. Make sure chrome://flags/#disable-webgl is disabled (there should be a link "Enable")
  2. If that does not help, try to additionally enable chrome://flags/#ignore-gpu-blacklist.

Exporting to Excel from Rails without a gem

See this Railscast.

Basically you can simply write views like index.xlsx.erb:

<?xml version="1.0"?>
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
  xmlns:o="urn:schemas-microsoft-com:office:office"
  xmlns:x="urn:schemas-microsoft-com:office:excel"
  xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
  xmlns:html="http://www.w3.org/TR/REC-html40">
  <Worksheet ss:Name="Sheet1">
    <Table>
      <Row>
        <Cell><Data ss:Type="String">ID</Data></Ce...

Be careful when using buttons without a "type" attribute

Be careful when using buttons without a type attribute, since browsers will consider them the default submit button of a form.

Suppose you have this form:

<form action="/save">
  <input type="text" />
  <button onclick="alert('Alert!')">Alert</button>
  <button type="submit">Save</button>
</form>

If you press the enter key inside in the text input, browsers will trigger the first button and show the alert.

To fix this, add a type="button" attribute to the first button.

How to create memory leaks in jQuery

jQuery doesn't store information about event listeners and data values with the element itself. This information is instead stored in a global, internal jQuery cache object. Every time you add an event listener or data value to a jQuery object, the jQuery cache gains another entry.

The only way that a jQuery cache entry gets deleted is when you call remove() on the element that put it there!

Since cache entries also have a pointer back to the element that spawned them, it is easy to create DOM elements that can never be garbage-co...

An auto-mapper for BEM classes in Cucumber selectors

When you are using the #selector_for helper in Cucumber steps, as e.g. Spreewald does, the following snippet will save you typing. It recognizes a prose BEM-style selector and maps it to the corresponding BEM class.

For a variation on this idea, see An auto-mapper for ARIA labels and BEM classes in Cucumber selectors.

Examples

"the main menu" -> '.main-menu'
"the item box's header" -> '.item-box--header'

Here are some examples of steps (using Spreewald, too):

T...

Did you know 'tig status' ?

It's like a GUI for the famous git add [-p].

Select files with the up/down-keys and hit

  • u for staging/unstaging the whole file
  • Enter for showing the diff of a file
    • j and k to navigate in the diff
    • u again to stage/unstage chunks
    • 1 to stage/unstage only lines
    • \ to split large chunks
  • F5 to refresh the view

Git: How to get a useful diff when renaming files

tldr; Use git diff -M or git diff --find-renames when you've moved a few files around.

Usage

$ git diff --help
  Options:
    -M[<n>], --find-renames[=<n>]
      Detect renames. If n is specified, it is a threshold on the similarity index
       (i.e. amount of addition/deletions compared to the file’s size). For example,
       -M90% means Git should consider a delete/add pair to be a rename if more than
       90% of the file hasn’t changed. Without a % sign, the number is to be read as
       a fraction, with a decimal point...

Angular + ui-router: Make links work in a new tab

If your angular app is not served on /, but on a different url (say /admin), links generated with ui-router will not work when you open them in a new tab.

Fix this by adding this tag in your <head>:

<base href='/admin#/'>

Helper method:

def base_tag
  tag(:base, href: request.path_info + "#/")
end

Debugging "INTERNAL ERROR!!! wrong argument type StringIO (expected File)"

If you're getting this strange error message when setting debugging breakpoints, probably HAML is the culprit.

Cause

As far as I could find out, the error is the result of setting a breakpoint (debugger) in a helper method that's called from a haml partial.

Suggestions

Try putting the breakpoint into the HAML view.

Geordi 1.0 released

Geordi 1.0 features a command line application geordi, that holds most of Geordi's previous commands.

New features

  • command help and usage examples right within geordi (geordi help and geordi help <command>)

  • quick command access: type just the first few letters of a command, e.g. geordi rs or geordi dev[server]

  • command dependencies, e.g. geordi rspec invokes geordi bundle-install (which bundles only if needed)

  • no cluttered /usr/bin, but all commands in one handy tool

  • template for easily adding new...

How to view a file from another branch

Just run git show branch:file. Examples:

git show HEAD~:bin/command
git show origin/master:../lib/version.rb

Jasmine: Testing AJAX calls that manipulate the DOM

Here is a Javascript function reloadUsers() that fetches a HTML snippet from the server using AJAX and replaces the current .users container in the DOM:

window.reloadUsers = ->
  $.get('/users').then (html) ->
    $('.users').html(html)

Testing this simple function poses a number of challenges:

  • It only works if there is a <div class="users">...</div> container in the current DOM. Obviously the Jasmine spec runner has no such container.
  • The code requests /users and we want to prevent network interaction in our uni...

velesin/jasmine-jquery

This jasmine plugin helps with testing DOM manipulation in two ways:

  1. It gives you DOM-related matchers like toBeVisible() or toHaveCss(css)
  2. It gives you a function to load HTML from fixture files. Without this you would have to manually add elements to <body> and clean up afterwards.

AngularJS: Binding to Perl-style getter/setters functions

Angular 1.3+ has an alternative getter/setter pattern: You can bind ng-model to an accessor function. This is a function that is either a getter (when it gets no arguments) or a setter (when it gets the new value as an argument):

$scope.name = function(newName) {
  return angular.isDefined(newName) ? (_name = newName) : _name;
}

You need to bind this function with ng-model and `ng-model-options="{ getterSette...

Taking screenshots in Capybara

Capybara-screenshot can automatically save screenshots and the HTML for failed Capybara tests in Cucumber, RSpec or Minitest.

Requires Capybara-Webkit, Selenium or poltergeist for making screenshots. Screenshots are saved into $APPLICATION_ROOT/tmp/capybara.

Manually saving a page

Additionally you can trigger the same behavior manually from the test using Capybara::Session#save_and_open_page and [...