Rails 4.0 has been out now for a while. It’s brought some great new features but as always there have been a few bugs too. And two of them that have been annoying me especially much will be fixed in Rails 4.1. Hooray! \o/

1. has_one associations will stop always using ORDER BY id

Best to illustrate this with an example (taken from the corresponding rails/rails#12623 issue)

class User < ActiveRecord :: Base has_one :profile end class Profile < ActiveRecord :: Base belongs_to :user end

In Rails 3.2 some_user.profile executed this database statement

SELECT * FROM profiles WHERE profiles . user_id = ? LIMIT 1

but starting with Rails 4 first always used a default ORDER BY (rails/rails#5153) because good databases (PostgreSQL :) ) will optimize a query without an explicit order, which means calling User.first may return different users every time, while User.order(:id).first may not.

(FYI Rails 4.0 introduced take which doesn’t use a default order. Most of the time you probably want to write User.where(...).take instead of User.where(...).first )

Because of that in Rails 4.0 some_user.profile executed this database statement:

-- Rails 4 SELECT * FROM profiles WHERE profiles . user_id = ? ORDER BY profiles . id ASC LIMIT 1

You would think, why does it matter if I send the ORDER BY or not, the result set has only one row anyhow.

But if the stars are just right PostgreSQL will decide to use a different (slower) index depending on whether the ORDER BY is there or not. And yes I did run into that.

Marko Tiikkaja explained PostgreSQL’s thought process like this:

hey, this user_id is quite common, I bet if I just start scanning in id order, I’ll find one row quickly

Rails 4.1 (and the upcoming Rails 4.0.3) will go back to the old behavior.

-- Rails 4.1 SELECT * FROM profiles WHERE profiles . user_id = ? LIMIT 1

2. associations can be unscoped

This one is rails/rails#10643. Clark Giorgos posted a nice demo:

class Product default_scope deleted_at: nil end class OrderItem belongs_to :product belongs_to :unscoped_product , -> { unscoped }, foreign_key: :product_id , class_name: "Product" end OrderItem . joins ( :unscoped_product ). group ( :product_id ). count

leads to Rails executing this SQL:

SELECT COUNT ( * ) AS count_all , product_id AS product_id FROM "order_items" INNER JOIN "products" ON "products" . "id" = "order_items" . "product_id" AND "products" . "deleted_at" IS NULL -- This should NOT be here GROUP BY product_id

And starting with Rails 4.1 this will be fixed. \o/