You know everything about pretending to be an ActiveRecord::Base object, 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 API 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:
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