---
title: Quacking like an ActiveRecord in Rails 2.3.4
teaser:
tags: web,rails
author: Mike Burns
published_on: 2009-09-10
---

You know everything about [pretending to be an `ActiveRecord::Base`
object](https://thoughtbot.com/blog/post/159805369/search-by-quacking-like-activerecord),
and especially the bit about ActiveRecord::Errors. That part's really cool.

What we are doing here is making an object that quacks like an
`ActiveRecord::Base` object but has no database table backing it. As examples: a
search object, a credit card object, or a remote user object. To do this, you
need `id`, `new_record?`, and the attributes must work in a specific fashion.
You can also have `errors` produce an `ActiveRecord::Errors` instance so user
errors will show in forms and whatnot.

However you may not have noticed that Rails 2.3.4 broke <abbr title="Application
Programming Interface">API</abbr> compatibility for `ActiveRecord::Errors`. If
your `ActiveRecord::Base`-like class provides an `#errors` instance method, it
must now provide these class methods:

* `self_and_descendants_from_active_record`, which produces an array of classes.
* `human_name`, which takes an optional hash and produces a string.
* `human_attribute_name`, which takes a string and optional hash and produces a
  string.

The last two of these methods are useful in your day-to-day Rails knowledge (the
first is an internal, undocumented method used by Rails to produce the class
itself and its parents, up to and excluding `ActiveRecord::Base`).

`human_name` is used to produce a humanized string representing the class/table
name. If your class is named `AuthenticationRecord`, `.human_name` will produce
`"Authenticationrecord"`. Any options you pass to this are normally sent to
`I18n.translate`.

`human_attribute_name` is used to map an attribute to a human-readable string.
For example, the attribute `created_at` is mapped to `"Created at"`. Any options
passed to this are normally sent to `I18n.translate`.

Here are some tests that need to pass now:

```ruby
class SearchTest < ActiveSupport::TestCase
  should "conform to the ActiveRecord::Errors interface" do
    assert_respond_to Search, :self_and_descendants_from_active_record
    assert_respond_to Search, :human_name
    assert_respond_to Search, :human_attribute_name

    assert_equal [Search], Search.self_and_descendants_from_active_record
    assert_equal "Search", Search.human_name
    assert_equal "Published at", Search.human_attribute_name('published_at')
  end
end
```
