Heads up: RSpec's diffs may not tell the truth

RSpec provides a nice diff when certain matchers fail.

Here is an example where this diff is helpful while comparing two hashes:

{a:1}.should match(a:1, b:2)

Failure/Error: {a:1}.should match(a:1, b:2)
  expected {:a=>1} to match {:a=>1, :b=>2}
  Diff:
  @@ -1,3 +1,2 @@
   :a => 1,
  -:b => 2,

Unfortunately, this diff is not as clever as it would need to. RSpec's instance_of matchers will look like errors in the diff (even if they are not), and time objects that differ only in milliseconds won't appear in the ...

Don't open user-supplied links with target="_blank"

This will give the target site full access to your Javascript environment through window.opener, if the target is on the same domain.

Even if the target site is on another domain, it still has some access and can for example manipulate window.location to perform a phishing attack.

You may use a rel="noopener" attribute to avoid this in modern browsers, except IE or Edge.

How to fix routing error when using concerns in Rails up to 3.2.22.1

tl;dr

  • Don't write resources :people, :concerns => :trashable

  • Write

    resources :people do
      concerns :trashable
    end
    

Why

Writing a controller spec I encountered this error:

Failure/Error: get :index
ActionController::RoutingError:
  No route matches {:controller=>"people"}

caused by this route definition

resources :people, :concerns => :trashable

which renders strange routes:

      trash_person PUT    /people/:id/trash(.:format)             people#check {:concerns=>:trashable}
          ...

nginx: How to drop connections for a location

If you want to configure your nginx to drop connections to a specific location, you can do so by responding with HTTP response code 444.

Status 444 is a non-standard response code that nginx will interpret as "drop connection".

Example:

server {
  listen 127.0.0.1;
  
  location /api/ {
    return 444;
  }
}

An example use case is reverse-proxying with nginx and simulating a route that drops connections.

Rails route namespacing (in different flavors)

TL;DR There are three dimensions you can control when scoping routes: path helpers, URL segments, and controller/view module.

scope module: 'module', path: 'url_prefix', as: 'path_helper_name' do
  resources :examples, only: :index
end

as → prefixes path helpers: path_helper_name_examples_path and path_helper_name_examples_url
path → prefixes URL segments: /url_prefix/examples
module → nests the controller: controller Module::ExamplesController, found at app/controllers/module/examples_controller.rb with views ...

Testing ActiveRecord callbacks with RSpec

Our preferred way of testing ActiveRecord is to simply create/update/destroy the record and then check if the expected behavior has happened.

We used to bend over backwards to avoid touching the database for this. For this we used a lot of stubbing and tricks like it_should_run_callbacks.

Today we would rather make a few database queries than have a fragile test full of stubs.

Example

Let's say your User model creates a first Project on cr...

One-liner syntax in RSpec's should-based and expect-based syntaxes

RSpec supports a one-liner syntax for setting an expectation on the subject:

describe Array do
  describe "when first created" do
    it { should be_empty }
  end
end

The example description "it should be empty" will be defined automatically.

With RSpec 3's expect-based syntax you use it_is_expected instead:

describe Array do
  describe "when first created" do
    it { is_expected.to be_empty }
  end
end

Testing ActiveRecord validations with RSpec

Validations should be covered by a model's spec.

This card shows how to test an individual validation. This is preferrable to save an entire record and see whether it is invalid.

Recipe for testing any validation

In general any validation test for an attribute :attribute_being_tested looks like this:

  1. Make a model instance (named record below)
  2. Run validations by saying record.validate
  3. Check if record.errors[:attribute_being_tested] contains the expected validation error
  4. Put the attribute into a valid state
  5. Run...

RSpec 3 argument constraints use weak equality

If you expect method calls in RSpec 3, be aware that the argument matchers use very liberal equality rules (more like === instead of ==).

For example:

expect(subject).to receive(:foo).with(MyClass)

subject.foo(MyClass)      # satisfies the expectation
subject.foo(MyClass.new)  # also satisfies the expectation

expect(subject).to receive(:bar).with(/regex/)

subject.bar(/regex/)      # satisfies the expectation
subject.bar('regex')      # also satisfies the expectation

This is usually not an issue, except when your method ...

IIFEs in Coffeescript

In JavaScript we often use Immediately Invoked Function Expessions (or IIFEs) to prevent local variables from bleeding into an outside scope:

(function() {
  var foo = "value"; // foo is scoped to this IIFE
})();

In Coffeescript an IIFE looks like this:

(->
  foo = "value" # foo is scoped to this IIFE
)()

There is also a shorthand syntax with do:

do ->
  foo = "value" # foo is scoped to this IIFE

You can also use do with arguments t...

RSpec: be_true does not actually check if a value is true

Don't use be_true to check if a value is true. It actually checks if it anything other than nil or false. That's why it has been renamed to be_truthy in recent RSpec versions.

The same thing holds for be_false, which actually checks if a value is not "truthy".

If you want to check for true or false in RSpec 2, write this instead:

value.should == true
value.should == false

If you want to check for true or false in RSpec 3+, write this instead:

e...

NoMethodError: undefined method `cache' for Gem:Module

I got this error when running Rails 2.3 tests for Rails LTS. More stacktrace:

NoMethodError: undefined method `cache' for Gem:Module
    /vagrant/rails-2-3-lts-repository/railties/lib/rails_generator/lookup.rb:212:in `each'
    /vagrant/rails-2-3-lts-repository/railties/lib/rails_generator/lookup.rb:146:in `to_a'
    /vagrant/rails-2-3-lts-repository/railties/lib/rails_generator/lookup.rb:146:in `cache'
    /opt/vagrant_ruby/lib/ruby/1.8/fileutils.rb:243:in `inject'
    /vagrant/rails-2-3-lts-repository/railties/l...

Geordi 1.3 released

Changes:

  • Geordi is now (partially) tested with Cucumber. Yay!
  • geordi cucumber supports a new @solo tag. Scenarios tagged with @solo will be excluded from parallel runs, and run sequentially in a second run
  • Support for Capistrano 2 AND 3 (will deploy without :migrations on Capistrano 3)
  • Now requires a .firefox-version file to set up a test firefox. By default now uses the system Firefox/a test Chrome/whatever and doesn't print warnings any more.
  • geordi deploy --no-migrations (aliased -M): Deploy with `cap ...

ActiveRecord meets database views with scenic

Using Scenic, you can bring the power of SQL views to your Rails application without having to switch your schema format to SQL. Scenic provides a convention for versioning views that keeps your migration history consistent and reversible and avoids having to duplicate SQL strings across migrations. As an added bonus, you define the structure of your view in a SQL file, meaning you get full SQL syntax highlighting in the editor of your choice and can easily test your SQL in the database console during development.

[https://robots.thoughtb...

Toggling a maintenance page with Capistrano

Note

Maintenance mode is enabled on application server as soon as the file /public/system/maintenance.html is present.

Note that the servers must be configured accordingly.

Installation

Add this line to your application's Gemfile:

 gem 'capistrano', '~> 3.0'
 gem 'capistrano-maintenance', '~> 1.0'

Add this line to you application's Capfile:

require 'capistrano/maintenance'

Enable task

Present a maintenance page to visitors. Disables your application's web interface by writing a `#{maintenanc...

bash: print columns / a table

Ever wondered how you can create a simple table output in bash? You can use the tool column for creating a simple table output.

Column gives you the possibility to indent text accurate to the same level. Pipe output to column -t (maybe configure the delimeter with -s) and see the magic happening.

detailed example

I needed to separate a list of databases and their corresponding size with a pipe symbol: |
Here is a example list.txt:

DB	Size_in_MB
foobar	11011.2
barfoo	4582.9
donkey	4220.8
shoryuken	555.9
hadouken	220.0
k...

yujinakayama/transpec: The RSpec syntax converter

A comprehensive script to convert test suites from RSpec 2 to RSpec 3. This converts more than should/expect syntax.

How to render an html_safe string escaped

Once Rails knows a given string is html_safe, it will never escape it. However, there may be times when you still need to escape it. Examples are some safe HTML that you pipe through JSON, or the display of an otherwise safe embed snippet.

There is no semantically nice way to do this, as even raw and h do not escape html_safe strings (the former just marks its argument as html_safe). You need to turn your string into an unsafe string to get the escaping love from Rails:

embed = javascript_tag('var foo = 1337;') # This is an h...

Geordi 1.2 released

Changes:

  • Remove some old binaries (commands still exist in geordi) and mark others as deprecated
  • Rewrite deploy command to support most deploy scenarios:
    • master to production
    • feature branch to staging
    • master to staging or production to production (plain deploy)
  • Improve Cucumber command (fixes #18):
    • Fix pass-through of unknown options to Cucumber
    • Add --rerun=N option to rerun failed Cucumber tests up to N times. Reboots the test environment between runs, thus will pick up fixes you made durin...

How to open a new tab with Selenium

Until recently, you could open a new tab via window.open when using execute_script in Selenium tests. It no longer works in Chrome (will show a "popup blocked" notification).

This is because browsers usually block window.open unless the user interacted with an element for security reasons. I am not sure why it did work via Selenium before.

Here is an approach that will insert a link into the page, and have Selenium click it:

path = "/your/path/here"
id = "helper_#{SecureRandom.hex(8)}"
execute_script <<-JAVASCRIPT
  ...

Using regular expressions in JavaScript

Regular expressions in Javascript are represented by a RegExp object. There also is a regex literal as in many other languages: /regex/. However, they are used slightly differently.

Regex literal

  • Usage: /foo+/
  • Shorthand for creating a regular expression object

RegExp() object

  • Usage: RegExp("foo+") or new RegExp("foo+")
  • No surrounding slashes required (they're the literal markers)
  • Since the argument is a string, backslashes need to be escaped as well: RegExp("\\d+")

Gotchas

  • Regex objects [never eq...

RSpec & Devise: How to sign in users in request specs

You know that Devise offers RSpec test helpers for controller specs. However, in request specs, they will not work.

Here is a solution for request specs, adapted from the Devise wiki. We will simply use Warden's test helpers -- you probably already load them for your Cucumber tests.

First, we define sign_in and sign_out methods. These will behave just like ...

Defining and calling lambdas or procs (Ruby)

Ruby has the class Proc which encapsulates a "block of code". There are 2 "flavors" of Procs:

  • Those with "block semantics", called blocks or confusingly sometimes also procs
  • Those with "method semantics", called lambdas

lambdas

They behave like Ruby method definitions:

  • They are strict about their arguments.
  • return means "exit the lambda"

How to define a lambda

  1. With the lambda keyword

    test = lambda do |arg|
      puts arg
    end
    
  2. With the lambda literal -> (since Ruby 1.9.1)
    ...

Stop writing "require 'spec_helper'" in every spec

Simply add this to your .rspec instead:

--require spec_helper

If you are on rspec >= 3 and use a rails_helper.rb require this instead of the spec_helper:

--require rails_helper

If you are using parallel_tests and this is not working for you, .rspec might be ignored. Try using a .rspec_parallel file.