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
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
human_name is used to produce a humanized string representing the class/table name. If your class is named
.human_name will produce
"Authenticationrecord". Any options you pass to this are normally sent to
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
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