Rails: When defining scopes with class methods, don't use `self`

Sometimes it is useful to define a named scope by implementing a static method with the scope's name on the scoped class. For instance, when a method should decide which existing scope should be the next link in the scope chain. Take this class for example:

class Meal < ActiveRecord::Base

  named_scope :for_date, lambda { |date| :conditions => { :date => date }}
  named_scope :with_meat, :conditions => { :meat => true }
  named_scope :without_meat, :conditions => { :meat => false }

  def self.suitable_for(user)
    if user.vegetar...

MySQL: "LOAD DATA INFILE" says "file not found"

This might be due to AppArmor denying the MySQL server access to most of the filesystem. You can instead use
LOAD DATA LOCAL INFILE ...
to pipe data through the MySQL client, which can read everything the executing user can.

Properly sanitizing column names for MySQL

There are times when you need to send SQL to the database, like this:

def self.some_count(field)
  field = connection.quote_column_name(field)
  scoped(:select => "COUNT(DISTINCT #{field}) AS count")
end

Although the given variable is sanitized here, the MySQLAdapter's (and probably other adapters as well) method for this is insufficient as it only wraps backticks around it, not helping against injection:

Klass.some_count("id`); DELETE FROM users; -- ")
# Will result in this SQL which is valid but definitely undesi...

How to define constants with traits

When defining a trait using the Modularity gem, you must take extra steps to define constants to avoid caveats (like when defining subclasses through traits).

tl;dr

In traits, always define constants with explicit self.

If your trait defines a constant inside the as_trait block, it will be bound to the trait module, not the class including the trait.
While this may seem unproblematic at first glance, it becomes a problem when including trai...

ETags with memcached

I love ETags, but there’s something that annoys me: most implementations revolve around pulling a record out of a data store and only “rendering” the response if it hasn’t been modified. 

The problem with this approach is that request has already gone through most of your application stack–parsing params, authentication, authorization, a few database lookups–so ETags are only saving you render time and some bandwidth.

While working on a Sinatra-based JSON web service that gets very heavy traffic, I wanted to find a way to short-circuit...

Always show the page if there is an error in Cucumber

Are you adding a "Then show me the page" and re-run Cucumber whenever there is a failing scenario? Don't be that guy!

Save time with the shiny new version of our cucumber_spinner gem. It comes with a Cucumber formatter that not only displays an awesome progress bar, and shows failing scenarios immediately, it will also open the current page in your browser whenever a scenario step fails.

After you installed the gem, use the formatter like this:

cucumber --format CucumberSpinner::Curiou...

Concurrency issues with find-as-you-type boxes

Find-as-you-type boxes are usually built by observing changes in a text field, and querying the server via AJAX for search results or suggestions when the field has changed.

A common problem with this implementation is that there is no guarantee that AJAX responses are evaluated in the same order as the original requests. The effect for the user is that the search results are flashing back and forth while the user is typing the query, and when the user has stopped typing the last results don't always match the final query.

Workarounds
----...

Speed up RSpec by deferring garbage collection

Update: This trick probably isn't very useful anymore in Ruby 2.x. The Ruby GC has improved a lot over the years.


Joe Van Dyk discovered that running the Ruby garbage collector only every X seconds can speed up your tests. I found that deferring garbage collection would speed up my RSpec examples by about 15%, but it probably depends on the nature of your tests. I also tried applying it to Cucumber f...

How to: Use git bisect to find bugs and regressions

Git allows you to do a binary search across commits to hunt down the commit that introduced a bug.

Given you are currently on your branch's HEAD that is not working as expected, an example workflow could be:

git bisect start # Start bisecting
git bisect bad # Tag the revision you are currently on (HEAD) as bad. You could also pass a commit's SHA1 like below:
git bisect good abcdef12345678 # Give the SHA1 of any commit that was working as it should
# shorthand:
git bisect start <bad ref> <good ref>

Git will fetch a comm...

Apache: Redirect all requests from one host to another

In order to redirect all requests from redirecting-host.com to desired-host.com while keeping path and query params unchanged, change your Apache VHost to something like this:

ServerName desired-host.com
ServerAlias redirecting-host.com
RewriteEngine On
RewriteCond %{HTTP_HOST} !^desired-host.com$
RewriteRule ^.*$ http://desired-host.com%{REQUEST_URI} [R=301,L]

Take care to keep all those ^, $ and ! as seen in the example.

Export CSV from MySQL directly

If you need to export data from MySQL to a CSV, you can profit from really fast built-in methods.

This query writes the data to /tmp/geodb_coodinates.csv. And it's fast: Query OK, 337925 rows affected (0.86 sec)

SELECT * INTO OUTFILE '/tmp/geodb_coordinates.csv' FIELDS TERMINATED BY ',' ENCLOSED BY '"' ESCAPED BY '\\' LINES TERMINATED BY '\n' FROM geodb_coordinates;

Reset MySQL query cache

To clear the query cache in your MySQL database manually, e.g. for database profiling, execute the following command in your MySQL console:

RESET QUERY CACHE;

Apply a new callback to existing records

So you added a new callback to your model that (e.g.) caches some data when it is saved. Now you need to run that callback for the 10000 existing records in the production database. You have two options here:

  1. Write a clever migration, possibly by embedding the model into the migration script.
  2. Open the Rails console after deployment and re-save every single record. You should probably add two chores to your issue tracker so you won't forget t...

Check if a field or button is disabled with Cucumber

Using this step definition you can check if any form field (text field, checkbox, etc) or button is disabled:

Then the "Name" field should be disabled
  And the "Save" button should be disabled
But the "Locked" field should not be disabled

Capybara

This step part of Spreewald.

Webrat

Then /^"([^\"]*)" should( not)? be disabled$/ do |label, negate|
  attributes = field_labeled(label).element.attributes.keys
  attributes.send(negate ? :should_not : :should...

Preloaded associations are filtered by conditions on the same table

When you eagerly load an association list using the .include option, and at the same time have a .where on an included table, two things happen:

  1. Rails tries to load all involved records in a huge single query spanning multiple database tables.
  2. The preloaded association list is filtered by the where condition, even though you only wanted to use the where condition to filter the containing model.

The second case's behavior is mostly unexpected, because pre-loaded associations usually don't care about the circumstances under whi...

Use the contents of a WordPress database in your Rails app

These two models can be used to access the posts and associated comments of a WordPress database.

Git: Changing commit messages

To change the commit message of the latest (unpushed, unmerged) commit, you can use
git commit --amend

To change the commit message of an earlier (unpushed, unmerged) commit [COMMIT], you can do
git rebase -i COMMIT~

For a current version of git, you can simply mark the line with "reword", and git will ask you later for the new message.

For older versions:

  • mark the line with edit
  • save the file
  • do a git commit --amend when rebasing stops at the relevant commit
  • git rebase --continue

Hints for debugging MySQL InnoDB deadlocks

Deadlocks only occur if two transactions in separate threads compete for the same rows in the database. They usually (but not necessarily) only happen when trying to update or otherwise lock several rows in different order.

Solving deadlocks is potentially complicated, so here are a few pointers:

  • MySQL should always detect the deadlock right when it happens, and will throw an error to one of the offending threads. This error states the SQL statement that this thread was currently waiting for, and that tried to acquire one of the competin...

Git: Amending older commits

Lets say you need to make a change to a commit OLD_COMMIT, but this is not the most recent. If you have neither pushed nor merged it, you can do this:

  • Make a new commit now, with a message like "fix".
  • Do a
git rebase -i OLD_COMMIT~
  • In the editor window that opened, move the "fix" commit directly after the one you want to amend (so it should be the second from the top), and mark it as "fixup". Save the file.
  • If there are conflicts, solve them, add them, and do
git rebase --continue

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...

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:

...

Virtual attributes for integer fields

Note that this card is very old. You might want to use ActiveType for your auto-coerced virtual attributes instead.


We sometimes give our models virtual attributes for values that don't need to be stored permanently.

When such a virtual attribute should contain integer values you might get unexpected behavior with forms, because every param is a string and you don't get the magic type casting that...

Don't use migrations to seed default data

Don't insert table rows in a Rails database migration. This will break tests that expect that database to be empty and cause you all sorts of pain.

If you need a place for default application data, use db/seed.rb or put a script into lib/scripts. It won't run automatically, so add a chore story to Pivotal Tracker as a reminder.