Rails 4.2: ActiveJob, Adequate Record, and foreign keys
The Rails 4.2 release candidate is out. A look at the three changes that matter most — a unified background-job API, a quietly large performance gain in ActiveRecord, and foreign keys finally landing in migrations.
The Rails 4.2 release candidate has landed, with the final not far behind. It is a focused release — three headline features and a scattering of smaller ones — but each headline addresses something developers have worked around for years. We have been running the betas, and here is what 4.2 actually changes for the way you build Rails apps.
ActiveJob: one API for background work
Every non-trivial Rails app pushes slow work into the background — sending email, processing uploads, calling third-party APIs. The trouble has always been that the queueing libraries are incompatible: Sidekiq, Resque, Delayed Job, and the rest each have their own way to define and enqueue a job. Switch backends and you rewrite all your job code; write a gem that needs background work and you cannot know which backend the host app uses.
ActiveJob fixes this by being the adapter layer Rails was missing — a single, backend-agnostic API for declaring and enqueuing jobs:
class ThumbnailJob < ApplicationJob
queue_as :default
def perform(upload)
upload.generate_thumbnail!
end
end
ThumbnailJob.perform_later(upload) # enqueue
ThumbnailJob.set(wait: 1.hour).perform_later(upload) # enqueue, delayed
You write your jobs once against ActiveJob, and a one-line config picks the actual queue backend:
config.active_job.queue_adapter = :sidekiq
Swap :sidekiq for :resque or :delayed_job and not a line of job code changes.
Two things make this more than a thin wrapper. First, GlobalID: ActiveJob
serialises ActiveRecord objects by a global identifier and reloads them in the
worker, so you can pass a model to perform_later and receive the model (not a raw
id) in perform — a small convenience that removes a lot of boilerplate. Second,
Action Mailer integration: deliver_later now sends email through ActiveJob, so
“send this email in the background” is finally a framework-level, backend-agnostic
one-liner instead of per-backend glue.
The honest caveat: ActiveJob is an abstraction over backends that still differ in real ways (retries, dead-job handling, concurrency). It standardises the interface, not every behaviour, so you still choose Sidekiq or Resque for their actual characteristics — you just stop coupling your job code to that choice.
Adequate Record: free performance
The most cheekily-named feature is also the one you do nothing to get. “Adequate Record” is a substantial internal optimisation of ActiveRecord that caches the computed SQL and prepared statements for common query patterns. The first time you run a particular shape of query, AR does the work of building it; subsequent identical-shape queries reuse the cached plan and skip a chunk of that overhead.
# the SECOND and later calls of this shape are noticeably faster,
# because the generated SQL / prepared statement is cached
Post.find(1)
user.posts.where(published: true).to_a
The reported speed-ups on common operations like find and association loading are
roughly a 2× improvement, and you get them by upgrading — no code changes, no new
API. For read-heavy apps that issue the same query shapes millions of times, that is
a meaningful, free win. It is exactly the kind of unglamorous core work that makes
upgrading Rails worth it even when the headline feature list looks short.
Foreign keys in migrations, at last
This one is overdue and very welcome. For years, ActiveRecord let you declare associations in your models while leaving the database with no actual foreign key constraint — so referential integrity was enforced (at best) by application code and entirely absent at the database level. Delete a record another row referenced and the database would shrug; you were left with orphans and dangling references that some validation was supposed to prevent but, under concurrency or a stray script, did not.
4.2 brings foreign keys into the migration DSL as first-class citizens:
class AddForeignKeys < ActiveRecord::Migration
def change
add_foreign_key :comments, :posts
add_foreign_key :comments, :users, on_delete: :cascade
end
end
# or inline when creating the table:
create_table :comments do |t|
t.references :post, foreign_key: true
t.references :user, foreign_key: true
end
Now the database guarantees that a comment cannot reference a non-existent post,
and on_delete: :cascade lets you push deletion rules down to where they belong.
This is the database doing the job it is uniquely good at — enforcing invariants
that must hold no matter what code, script, or race tries to violate them. We have
long added these by hand in raw SQL migrations; having them in the DSL means they
are now the easy, default path, and more apps will get the integrity they should
have had all along. (Postgres and MySQL get this; SQLite’s support is limited, as
ever.)
The smaller additions
A few more worth noting: the Web Console gives you an interactive irb session
right in the browser on an error page (and via console in a view) — a genuinely
useful debugging aid, though one to keep firmly out of production. render gains
the ability to render templates from outside the controller’s own view paths. And
there is the usual round of ActiveSupport refinements and deprecation cleanups as
the framework keeps tidying itself.
Verdict
4.2 is a high-value, low-friction upgrade. ActiveJob is the standardisation
background processing always needed and immediately makes your job code more
portable and your mailers easier; Adequate Record hands you a real performance
improvement for the cost of bundle update; and foreign keys close a correctness
gap that has quietly bitten Rails apps for a decade. None of it requires you to
rewrite anything — adopt ActiveJob as you touch your jobs, add foreign keys in your
next migration, and enjoy the speed-up for free. This is Rails maturing in the best
way: not chasing novelty, but fixing the things that experienced teams had learned
to route around.