MySQL: Do not use "WHERE id IN (SELECT ....)"

Note: This applies specifically to MySQL. In PostgreSQL for example, this is not an issue.

If you care about performance, never use a query like

UPDATE users SET has_message = 1 WHERE users.id IN (SELECT user_id FROM messages)

MySQL does not optimize this and seems to scan the temporary table, which isn't indexed, for every row in the update statement. This applies to other statements than UPDATE as well.

Instead, either use a JOIN like

UPDATE users INNER JOIN messages ON messages.user_id = users.id SET has_message =...

How the Clearance gem remembers and clears sessions

Clearance is a gem that provides authentication functionality (e.g. login, logout). This note explains, how the clearance login, logout and (in old Clearances) remember me functionality works.

Login

Clearance defines a database column called "remember_token". When you login in, that token will be saved in a cookie. For that reason you don't have to re-sign-in when you close and open the browser again.
This also means that you can be logged in in more than a single browser. Also see [When ses...

How to use html_safe correctly

By default, Rails views escape HTML in any strings you insert. If you want to insert HTML verbatim, you need to call #html_safe. However, #html_safe does not "unescape" a string. It merely marks a string as safe for unescaped insertion.

How html_safe works

Calling html_safe on a String returns a new object that looks and acts like a String, but actually is a ActiveSupport::SafeBuffer:

"foo".length
# => 3
"foo".class
# => String

"foo".html_safe.length
# => 3
"foo".html_safe.class
# => ActiveSupport::S...

Cucumber.yml was found, but could not be parsed.

If you encounter the error message above when running cucumber, just execute...
rm rerun.txt
...in the Rails directory.

Or run...
tests
...from the geordi gem. This will do the work for you automatically.

Ruby 2.0 Implementation Work Begins: What is Ruby 2.0 and What’s New?

While 2.0 will include a number of syntax changes, new features and general improvements, mentioned below, it is anticipated to remain backward compatible with code written for 1.9.3 and Matz has stated that the changes are less significant than those made in the 1.8 to 1.9 jump.

Javascript equivalent of Ruby's array.collect(&:method)

The most common use case for Ruby's #collect is to call a method on each list element and collect the return values in a new array:

['hello', 'world', 'this', 'is', 'nice'].collect(&:length)
# => [5, 5, 4, 2, 4]

Although there is no equivalent to this idiom in naked Javascript, there is a way to collect object properties (but not method results) if you are using common Javascript libraries.

If you are using jQuery with the Underscore.js utility library, you can use [pluck](htt...

Monitor a Rake task with God

In order to monitor a Rake task using God your Rake file must write a file with its process ID (PID) to a path determined by God. This way God can check whether the Rake process is still alive.

Here is how to do this: In your God config, call the Rake task with an environment variable PIDFILE. This variable should equal the PID file path desired by God:

God.watch do |w|
  w.dir = "#{rails_root}"
  w.name = "my_task"
  w.interval = 10.seconds
  w.pid_file = "#{rails_root}/tmp/pids/#{w.name}...

Mailcatcher: An alternative to inaction_mailer

Looks simpler than inaction_mailer:

gem install mailcatcher
mailcatcher

Setup Rails to send mails to 127.0.0.1:1025. Usually you want the following config in config/environments/development.rb and maybe in test.rb or cucumber.rb.

config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
  :address => 'localhost',
  :port => 1025
}

Now you can see sent mails in your browser when opening http://127.0.0.1:1080

Note: In order to s...

Start Rails console or server with debugger

When you require the Ruby debugger to be available from your Rails console (e.g. you want to inspect a method's magic), you need to enable it explicitly:
script/console --debugger

If you cannot access local variables etc, see this card.

WEBrick

For WEBrick, enable it similarly:
script/server --debugger

Properly adding fields with default values to a model

When adding a new field to your model's database table, don't set any defaults in the database.

It makes people wonder why they get such values when reading attributes.\
Why? Because nobody looks at the database layout since such things are part of your application's logic -- and thus they belong into the corresponding model.

How to

Do it like this:

  • In your migration, after adding the field, update all fields to your desired default:

    update "UPDATE users SET locked = #{quoted_false};"
    
  • In your model, set a defau...

Install the Oniguruma gem

Oniguruma is an advanced regular expression engine for Ruby.

Install Oniguruma with binary dependencies like this:

sudo apt-get install libonig2 libonig-dev
sudo gem install oniguruma

On the Mac do:

brew install oniguruma
sudo gem install oniguruma

MySQL: For each group, retrieve a comma-separated list of values in a given column

The technique described in this card has an important caveat: The result of GROUP_CONCAT is truncated to the maximum length that is given by the group_concat_max_len system variable, which has a default value of 1024. This will cause horrible, data-destroying bugs in production. For this reason you should probably not use GROUP_CONCAT ever. At least you must set the value of group_concat_max_len to an insanely high value on every database server your application runs on.


Lik...

Using heredoc for prettier Ruby code

You can use heredoc to avoid endlessly long lines of code that nobody can read. Heredoc strings preserve linebreaks and can be used like this:

def long_message
  puts(<<-EOT)
    Here goes a very long message...
    Sincerely,
    foobear
  EOT
end

<<-EOT will be somewhat of a placeholder: anything you write in the line after you used it will be its value until you write EOT in a single line.

You can use any string to flag your heredocs. To be more verbose you...

How to fix: Gems are unavailable although they are installed

  • If Rails or Rake are complaining about a missing gem that is listed in your Gemfile.lock and the listed version is properly installed, something is seriously wrong and needs to be fixed.
  • If you accidently executed bundle install some_gem although you wanted bundle update some_gem

What is wrong

Let's say your Gemfile asks for some-gem which you can see when running gem list but bundle show some-gem just gives you an error:

Could not find gem 'some-gem', in any of the sources

Another indicator: Doing a `...

Use a Ruby method like a block or lambda

Sometimes you want to use a vanilla Ruby method like a block. You can use Object#method to obtain a method reference that responds to #call:

foo_plus = "foo".method(:+)
foo_plus.call("bar") # => "foobar"

The method reference also understands #to_proc so you can feed it to block-taking methods by prefixing it with &:

printer = method(:puts)
[1, 2, 3].each(&printer) # will print one line per number

Selenium WebDriver 2.5.0, 2.6.0 fails when selecting options from select boxes

We are consistently having trouble with selenium-webdriver > 2.5.0 where whenever we try to select an option from a <select> Capybara complains:

No such option 'Foo' in this select box. Available options: 'Foo', 'Bar', 'Baz' (Capybara::OptionNotFound)

This seems to happen with both old and new versions of Firefox. Our workaround so far is to freeze the gem at version 0.2.2.

sstephenson/execjs - GitHub

ExecJS lets you run JavaScript code from Ruby. It automatically picks the best runtime available to evaluate your JavaScript program, then returns the result to you as a Ruby object.

Auto-generate state_machine graphs as PNG images

The state_machine gem comes with a rake task that lets you generate PNG graphs from any model using state_machine.

Install the required dependencies like this:

sudo apt-get install graphviz
sudo gem install ruby-graphviz

You can now generate a graph like this:

rake state_machine:draw CLASS=ModelUsingStateMachine

Replace ModelUsingStateMachine with the name of your model class.


If it the raketask does not exist for you, add to Rakefile (in your pr...

Defining custom errors in Ruby

class Errormaster
  CoffeeIsOut = Class.new(StandardError)
  
  # is prettier than
  class CoffeeIsOut < StandardError; end
end

Reference such an error class with Errormaster::CoffeeIsOut.

How to install a frozen version of Firefox for your Selenium tests

Whenever Firefox updates, all your Cucumber features that use Selenium break. This is annoying.

In order to remedy this, version 0.5.0 of our geordi gem comes with a script that helps you create an unchanging version of Firefox for your Selenium tests. In particular, this new copy of Firefox will have the following properties:

  • It won't update itself with a newer version
  • It can co-exist with your regular Firefox installation (which you can update at will)
  • It will use a profile separate from the one...

mojombo/grit - GitHub

Grit gives you object oriented read/write access to Git repositories via Ruby.

Rails 3.1.0 has been released!

jQuery as new default Javascript library, streaming response support, attr_accessible with roles, prepared statements, easier migrations.

Ruby: Convert a time string to your local time zone

If you have a time given in a different time zone than your local one, parsing will convert it for you:

>> Time.parse('September 2nd, 3pm PST')
=> 2011-09-03 01:00:00 +0200

Note that in pure Ruby you need to require "tzinfo" (Ruby 1.9) or require "time" (Ruby 1.8) for Time.parse to be available.

Fix: "undefined method `bytesize' for #<Array>"

I believe that when WEBrick has trouble bringing up your Rails application, the WEBrick component that is supposed to print you a pretty error message has a bug and sometimes fails with this message:

"undefined method `bytesize' for #<Array>"

Starting the application in Passenger gave me a stacktrace in log/development.log that pointed to the actual problem.

Possible causes discovered by looking at the logs
-----------------------------------------------------...