Capistrano cowboy deploys

Sometimes, you just need to shoot from the hip…or deploy your local changes without committing them. Put this snippet from Jesse Newland in ~/.caprc and now you can cap cowboy deploy.

Ruby: Checking if a class is a descendant of another class

If you want to find out whether a Class object is directly inheriting from another class, use superclass:

ActiveRecord::RecordNotFound.super_class == ActiveRecord::ActiveRecordError # => true

To check if another class is an ancestor (not necessarily the direct superclass, but e.g. the superclass of the superclass):

ActiveRecord::RecordNotFound.ancestors.include?(StandardError) # => true

Note that ancestors also includes the receiving class itself as well as any included modules (which is quite...

Check if two arrays contain the same elements in Ruby, RSpec or Test::Unit

RSpec 1, RSpec 2

To test whether two arrays have the same elements regardless of order, RSpec 1 and 2 give you the =~ matcher:

actual_array.should =~ expected_array

Rspec 3

With RSpec 3's expect syntax you can choose one of these two matchers:

expect(actual_array).to match_array(['1', '2', '3'])
expect(actual_array).to contain_exactly('1', '2', '3')

Note how match_array takes an argument, but contain_exactly takes a list of elements as varargs.

Test::Unit

If y...

Encode or decode HTML entities

Use the htmlentities gem.

Encoding works like this:

require 'htmlentities'
coder = HTMLEntities.new
string = "<élan>"
coder.encode(string)               # => "&lt;élan&gt;"
coder.encode(string, :named)       # => "&lt;&eacute;lan&gt;"
coder.encode(string, :decimal)     # => "&#60;&#233;lan&#62;"
coder.encode(string, :hexadecimal) # => "&#x3c;&#xe9;lan&#x3e;"

Decoding works like this:

require 'htmlentities'
coder = HTMLEntities.new
string = "&eacute;lan"
cod...

Never use YAML.load with user input

You can get YAML.load to instantiate any Ruby object by embedding the desired class name into the YAML code. E.g. the following will create a new User object and set @email and @password to the given values:

--- !ruby/object:User
email: me@somewhere.com
password: secret

Considering the security implications, you should never trust YAML from untrusted sources. If you are looking for a simple, secure and readable data transfer format, use Object#to_json and JSON.parse.

Another way around YAML.load is [`YAML.safe_...

Open a page in the default browser

Use the Launchy gem:

Launchy.open('http://www.ruby-lang.org/')

Change the current directory without side effects in Ruby

To temporarily change the current working directory in Ruby, call Dir.chdir with a block. The previous working directory will be restored when the block ends:

Dir.chdir('/usr/local') do
  # do stuff in /usr/local
end

Ruby 2.0 Refinements in Practice

The first thing you need to understand is that the purpose of refinements in Ruby 2.0 is to make monkey-patching safer. Specifically, the goal is to make it possible to extend core classes, but to limit the effect of those extensions to a particular area of code. Since the purpose of this feature is make monkey-patching safer, let’s take a look at a dangerous case of monkey-patching and see how this new feature would improve the situation.

MySQL: Select a default value for NULL fields

If you need to do calculations inside the database and can not use Ruby objects you may run into problems when encountering fields with NULL values:

SELECT foo, bar, foo - bar AS baz FROM plop;
+-----+------+------+
| foo | bar  | baz  |
+-----+------+------+
|  30 |   20 |   10 |
|  30 | NULL | NULL |
+-----+------+------+

Solve this by using IFNULL: it returns the selected value if present and a given alternative if it would select NULL:

SELECT foo, bar, foo - IFNULL(bar, 0) AS baz FROM plop;
+-...

Virtual attributes for array fields

When a has_many association basically serves to store a list of associated strings (tags, categories, ...), it can be convenient to represent this association as a string array in the containing model. Here is an example for this pattern from the acts-as-taggable-on gem:

post = Post.last
p post.tag_list # ['foo', 'bar', 'baz']
post.tag_list = ['bam']
p post.tag_list # ['bam']

This string array tag_list is magical in several ways:

  • It is read from and written to a `has...

Install RubyMine under Ubuntu

This card explains how to install RubyMine for the first time. If you want to upgrade an existing RubyMine installation (after legacy install) to a newer version, see How to upgrade RubyMine.


Option A (new way)

Ubuntu 16.04 comes with snap, a way to package software with all its dependencies. RubyMine is also packaged as a snap.

A snap will always track a channel (like stable, beta) and automatically update to the newest version available in this channel. By default the snap daemon will check for ...

Installing Nokogiri

Because Nokogiri needs to be compiled and dynamically linked against both libxml2 and libxslt, it has gained a reputation for being complicated to install. Let’s wrassle this little myth to the ground, shall we?

Hunt down that elusive debug message in Ruby

When you just went through a long debug-fest and infested your code with dozens of debug messages, it can be hard to find all those calls to puts and p. This note describes a hack that lets you trace those messages in your code.

Let's say you want to get rid of a console message "foobar". Copy the Undebug class below to config/initializers.rb. In the same initializer, type a line:

Undebug.trace_message('foobar')

Now run tests or whatever you need to do to to trigger that message. The console output should look like this:

...

Take care when joining and selecting on scopes

Occasionally some complex query must be processed on the database because building thousands of Ruby objects is impracticable.

Many times you would use scope options, like this:

users = User.scoped(
  :joins => 'INNER JOIN orders joined_orders ON users.id = joined_orders.user_id',
  :conditions => [ 'joined_orders.date BETWEEN ? AND ?', start_date, end_date ],
  :select => '*, SUM(joined_orders.amount) AS amount_sum',
  :group => 'users.id'
)

You get ActiveRecord objects and you can ask each of them about its `amou...

Manipulate an array attribute using multiple check boxes

E.g. when you're using a tagging gem, you have seen virtual attributes that get and set a string array:

post = Post.last
puts post.tag_list # ['foo', 'bar', 'baz']
post.tag_list = ['bam']
puts post.tag_list # ['bam']

If you would like to create a form displaying one check box per tag, you can do this:

- form_for @post do |form|
  = form.check_box :tag_list, { :multiple => true }, 'foo', nil
  = form.check_box :tag_list, { :multiple => true }, 'bar', nil
  =...

Use the back button in Cucumber

In order to go back one page in your Cucumber tests, you can use the following step definition for Capybara:

When(/^I go back$/) do
  visit page.driver.request.env['HTTP_REFERER']
end

If you're on Webrat, this should work:

When(/^I go back$/) do
  visit request.env["HTTP_REFERER"])
end

An improved version of this step is now part of our gem spreewald on Github.

Test a gem in multiple versions of Rails

Plugins (and gems) are typically tested using a complete sample rails application that lives in the spec folder of the plugin. If your gem is supposed to work with multiple versions of Rails, you might want to use to separate apps - one for each rails version.

For best practice examples that give you full coverage with minimal repitition of code, check out our gems has_defaults and assignable_values. In particular, take a look at:

  • Multiple `sp...

Install a specific version of a gem

To install webmock 1.5.0:

sudo gem install webmock --version "=1.5.0"

or
sudo gem install webmock -v "=1.5.0"

Prevent Bundler from downloading the internet

As a user of Bundler you have spent significant time looking at this message:

Fetching source index for http://rubygems.org/

To make Bundler skip this index update and only use installed gems, you can use the --local option:

bundle install --local

Unfortunately this does not work with bundle update.

It is said that Bundler 1.1 will use a feature of Rubygems.org that allows partial index updates. Hopefully the wh...

Generate a Unicode nonbreaking space in Ruby

Regular spaces and non-breaking spaces are hard to distinguish for a human.
Instead of using the &nbsp; HTML entity or code like " " # this is an nbsp, use a well-named helper method instead.

def nbsp
  [160].pack('U*')
end

160 is the ASCII character code of a non-breaking space.

Defining and using sub-classes with modularity

Given this class:

class Foo
  class Bar
  end
end

If you want to clean up this code with the modularity gem, you might try something like this:

class Foo
  does 'bar'
end

module BarTrait
  as_trait do
    class Bar
    end
  end
end

Note that this changes Bar's full class name from Foo::Bar to BarTrait::Bar. If you have methods inside Foo (or other classes), you would have to change all references accordingly, which is quite unpleasant.

You can solve it like that:
`...

Install gems for all bundled projects

This is a bash script for those of you who need to install all gems for all projects (e.g. to get started quickly on a newly installed system).

Put it into your ~/bin/ and run it from the directory that holds your projects.

Note that, like the vanilla bundle install, this will fail whenever a new gem compiles native components and requires a missing system dependency.

Terminus: a client-side Capybara driver

Terminus is a Capybara driver where most of the driver functions are implemented in client-side JavaScript. It lets you script any browser on any machine using the Capybara API, without any browser plugins or extensions.

Standalone Cucumber Test Suite

Sometimes you inherit a non Rails or non Rack based web app such as PHP, Perl, Java / JEE, etc. I like using cucumber for functional testing so I put together this project structure to use as a starting point for testing non Ruby web based applications.