Automatically run bundle exec if required

There will probably be better solutions as we become more experienced with using Bundler, and more command line tools become Bundler-aware.

b will use bundle exec if there is a Gemfile in the working directory, and run the call without Bundler otherwise.

b spec spec

This script is part of our geordi gem on github.

Airbrake notification in Rake tasks

Put

def task_with_hoptoad_notification(options)
  task(options) do
    begin
      yield
    rescue Exception => e
      Airbrake.notify(e)
      raise e
    end
  end
end

at the top of the Rakefile, and replace all relevant

task :my_task => :environment do
    do_something
end

with

task_with_hoptoad_notification :my_task => :environment do
    do_something
end

This will use the usual notification rules, i.e. you won't get anything in the development or test environments.
...

Bundler for Rails 2.3.x

Update RubyGems and Passenger

Bundler requires Rubygems >= 1.3.6. Run gem update --system if you have an older version.
It also is not compatible with older versions of passenger, so bring that up to date as well (2.2.15 works).

If you installed RubyGems through apt (which you should never do!), you may see a message giving you a hint to use apt to update.
Some people advise to install the 'rubygems-update-1.3.7' gem on Ubuntu systems if you used apt to install RubyGems.
I did that - and lost all...

Rails: Preloading associations in loaded records

Sometimes you want to fetch associations for an ActiveRecord that you already loaded, e.g. when it has deeply nested associations.

Edge Rider gives your models a static method preload_associations. The method can be used to preload associations for loaded objects like this:

class UsersController < ApplicationController
  def show
    @user = User.find(params[:id])
    @user.preload_associations(threads: { posts: :author }, messages: :sender)
  end
end

The attached initializers re...

Defining custom RSpec matchers

There are three ways to define your own RSpec matchers, with increasing complexibility and options:

1) Use RSpec::Matchers.define

RSpec::Matchers.define :be_a_multiple_of do |expected|
  match do |actual|
    actual % expected == 0
  end
  
  # optional
  failure_message do |actual|
    "expected that #{actual} would be a multiple of #{expected}"
  end
  
  # optional
  failure_message_when_negated do |actual|
    "expected that #{actual} would not be a multiple of #{expected}"
  end
end
  • This is automatically available i...

Efficiently add an event listener to many elements

When you need to add a event listener to hundreds of elements, this might slow down the browser.

An alternative is to register an event listener at the root of the DOM tree (document). Then wait for events to bubble up and check whether the triggering element (event.target) matches the selector before you run your callback.

This technique is called event delegation.

Performance considerations

Because you only register a single listener, registering is ...

InfoQ: How to Design a Good API & Why it Matters

A well-written API can be a great asset to the organization that wrote it and to all that use it. Given the importance of good API design, surprisingly little has been written on the subject. In this talk (recorded at Javapolis), Java library designer Joshua Bloch teaches how to design good APIs, with many examples of what good and bad APIs look like.

Spec correct routing of custom URLs

When you roll custom URLs with hacks like routing-filter, you can put a spec like this into spec/routing/routing_spec.rb:

Test e-mail dispatch in Cucumber

Spreewald has steps that let you test that e-mails have been sent, using arbitrary conditions in any combination.

The attached file is for legacy purposes only.

Testing validates_format_of with Shoulda matchers

Don't use should validate_format_of(...) because that matcher works in weird ways. Use the allow_value matcher instead:

describe Email, '#sender' do
  # > Rspec 3 should syntax
  it { should allow_value("email@addresse.foo").for(:sender) }
  it { should_not allow_value("foo").for(:sender) }
  
  # Rspec 3 expect syntax
  it { is_expected.to allow_value("email@addresse.foo").for(:sender) }
  it { is_expected.not_to allow_value("foo").for(:sender) }
end

Errors that may occur if you do use should validate_format_of(...):
...

Regular Expressions - Cheat Sheet

You can write regular expressions some different ways, e.g. /regex/ and %r{regex}. For examples, look here.

Remember that it is always a good idea to match a regex visually first.

Characters

Literal Characters

[ ] \ ^ $ . | ? * + ( )

Character Classes

[ae]            matches a and e, e.g. gr[ae]y => grey or gray => but NOT graay or graey
[0-9]  ...

Multi-line step arguments in Cucumber

The following example is from the Cucumber wiki:

Given a blog post named "Random" with Markdown body
  """
  Some Title, Eh?
  ==============
  Here is the first paragraph of my blog post. Lorem ipsum dolor sit amet,
  consectetur adipiscing elit.
  """

That multi-line string will be given as the last block argument in your step definitions:

Given /^a blog post named "([^\"]*)" with Markdown body$/ do |title, markdown|
  Post.create!(:title =...

rspec_candy is now a gem

Our awesome collection of rspec helpers (formerly known as "spec_candy.rb") is now available as a gem. It works, it is tested and there will be updates.

Usage

Add rspec_candy to your Gemfile.

Add require 'rspec_candy/helpers' to your spec_helper.rb, after the rspec requires.

List of features

See on GitHub

Faking and testing the network with WebMock

An alternative to this technique is using VCR. VCR allows you to record and replay real HTTP responses, saving you the effort to stub out request/response cycles in close details. If your tests do require close inspection of requests and responses, Webmock is still the way.


WebMock is an alternative to FakeWeb when testing code that uses the network. You sh...

Forward HTTP through an intermediary server (Local Port Forwarding)

This will tunnel HTTP requests to one given domain and port through an intermediary SSH server:

ssh -L 8080:targethost:80 tunnelhost

http://localhost:8080 will now connect you to http://targethost:80, tunnelling all data through tunnelhost via SSH.

Note that the connection between tunnelhost and targethost will still be unencrypted in this example.

Submit a form with Prototype

For example, to send a form and populate a preview div with the response.

$('content_form').request({
  parameters: { 'preview': "1" }, // overrides parameters
  onComplete: function(transport){ 
    $('previewContent').update(transport.responseText); 
  }
});

defunkt's fakefs at master - GitHub

A fake filesystem. Use it in your tests.

Fixing Webrat after following an external link

When a Cucumber feature leaves your page through an external Link, Webrat has problems like "Could not find field: "E-mail" (Webrat::NotFoundError)" using your page afterwards. It will also have trouble following redirects.

Fix it with this step:

Given /^I am back on my page$/ do
  webrat_session.header("Host", "www.example.com")
end

MySQL replication how-to

This may be awkward to set up, but will work once you're done.

Fun facts:

  • In case of a connection loss the slave will try to reconnect to the master server and resume replication for the next 24 hours
  • If you want to use your slave as a "real" MySQL server, you basically need to switch off replication (STOP SLAVE; RESET SLAVE; and reset your my.cnf) and restart the MySQL daemon.

Master server configuration

  • Create replication user
    In the MySQL shell:
    CREATE USER 'replicator'@'%' IDENTI...
    

Cucumber Webrat steps

Most of these will not work in newer projects because these use the Capybara/Rack::Test combo in lieu of Webrat.

Find input fields

Then /^there should be a "([^"]+)" field$/ do |name|
  lambda { webrat.current_scope.send(:locate_field, name) }.should_not raise_error(Webrat::NotFoundError)
end

Then /^there should be no "([^"]+)" field$/ do |name|
  lambda { webrat.current_scope.send(:locate_field, name) }.should raise_error(Webrat::NotFoundError)
end

Find html content

Then /^I should see "([^\"]*)...

Aggregated RSpec/Cucumber test coverage with RCov

With defaults, RCov doesn't work the way you how you would like it to. To create a nice test coverage report, copy the attached file to lib/tasks/rcov.rake. After that rake rcov:all will run all RSpec examples and Cucumber features. The report will be written RAILS_ROOT/coverage/index.html.

Here is what the task does in detail:

  • Generates aggregated coverage of both RSpec and Cucumber
  • Works with Rails 2 and Rails 3
  • Reports for app/**/*.rb and nothing else
  • If called with an environment variable IGNORE_SHARED_TRAITS=true it ...

Better output for Cucumber

We built cucumber_spinner to have a progress bar for Cucumber features, which also outputs failing scenarios as soon as they fail.

Installation

gem install cucumber_spinner

Usage

cucumber --format CucumberSpinner::ProgressBarFormatter

If you use CucumberSpinner::CuriousProgressBarFormatter and a feature fails, the according page will show up in your browser.


Note that if you run your Cucumber tests using the [cuc](https://makandracards.com/makandra/1277-a-nicer-way-to-...

Test concurrent Ruby code

To test concurrent code, you will need to run multiple threads. Unfortunately, when you use blocking system calls (e.g. locks on the database), Ruby 1.8 threads won't work because system calls will block the whole interpreter.

Luckily you can use processes instead. fork spins off a new process, IO.pipe sends messages between processes, Process.exit! kills the current process. You will need to take care of ActiveRecord database connections.

Here is a full-fledged example:

describe Lock, '.acquire' do

  before :each do
  ...

Better Output for RSpec

rspec_spinner is a progress bar for RSpec which outputs failing examples as they happen (instead of all at the end).

Installation

gem install rspec_spinner

Usage

script/spec -r rspec_spinner -f RspecSpinner::Bar -c

To make a shortcut in your .bashrc

alias ss='script/spec -r rspec_spinner -f RspecSpinner::Bar -c'

There's also an alternate runner RSpecSpinner::Spinner which shows a spinner and the name of the current spec instead of a progress bar.