Jonathan, cool, it does exactly what I need and more, but
once we are at it let me raise some issues.
The way you define defaults, symbol values are called on the instance
This intends to capture the situation when an attribute is by default
assumes the value of another attribute (e.g.,
default :login, :first_name)
But where would the value of first name come from, if it is
initialized in new, its fine, but if it is itself a default, what
happens?
The problem is that the attribute setters are called in a random order
(that is determined by the access order of hash map), therefore
the behaviour in such cases is not even consistent.
Tag.write_inheritable_attribute(:attribute_defaults,nil)
=> nil
Tag.defaults :name => 2, :id => :name
=> [#<ActiveRecord::Defaults::Default:0xb6cb7878 @attribute="name",
@value=2>, #<ActiveRecord::Defaults::Default:0xb6cb7828
@attribute="id", @value=:name>]
Tag.new
=> #<Tag id: 2, name: 2, created_at: nil, updated_at: nil>
id is set after name
Tag.write_inheritable_attribute(:attribute_defaults,nil)
=> nil
Tag.defaults :id => :name, :name => 2
=> [#<ActiveRecord::Defaults::Default:0xb6cb0fa0 @attribute="name",
@value=2>, #<ActiveRecord::Defaults::Default:0xb6cb0f50
@attribute="id", @value=:name>]
Tag.new
=> #<Tag id: 2, name: 2, created_at: nil, updated_at: nil>
same when the order is changed. this is because setting :name
incidentally happens before setting :id
But when we want to set name to anything that id is:
Tag.write_inheritable_attribute(:attribute_defaults,nil)
=> nil
Tag.defaults :name => :id, :id => 2
=> [#<ActiveRecord::Defaults::Default:0xb6ca82c4 @attribute="name",
@value=:id>, #<ActiveRecord::Defaults::Default:0xb6ca8274
@attribute="id", @value=2>]
Tag.new
=> #<Tag id: 2, name: nil, created_at: nil, updated_at: nil>
OOPS then name is nil, since :id has no value at the time it is
called.
[Don't call me names for setting ids, this is just a demonstration
ok? ;-))
This also demonstrates another problem, which is that default
assignments are not consistent with what
can be given in the hash of the new constructor:
Tag.new(:name => :id)
=> #<Tag id: 2, name: :id, created_at: nil, updated_at: nil>
In this case the symbol translates to the string ':id' (bye the way,
how on earth does that then magically become "--- :id\n" after a
database save???)
For me it would also be feasible to interpret ':id' magically as a
string just like in "#{:id}" which gives "id"
which means that the default interpretation for symbols as methods is
at least not obvious.
Yet another thing: apart from belongs_to associations, the way you
determine whether defaults should be applied is you look
at whether the attribute was given to 'new'.
The other option was my solution to check whether an attributes reader
results in nil.
Your solution has the clear advantage that defaults CAN now be
overriden with nil
but it also assumes that no other attributes are ever set in the
original initialize unless explicitly mentioned in a keys given to
new?
Is this assumption correct (again apart from associations)?
Looking forward to your ideas
Viktor