I recall hearing the Holy Beasts of Doom argument for overriding new -
but not for initialize. I've been using something like Piers'
approach, which has always worked for me:
def initialize(attrs = {}, &block)
super attrs.reverse_merge(default_attributes_hash), &block
more_initialization_dependent_on_instance_already_being_built
end
I see the problem with string-versus-symbol keys, but Rails has had
that problem for a long time as well as tolerable solutions
(HashWithIndifferentAccess, or the manual equivalent).
Unless somebody has some good evidence of why overriding initialize is
inherently dangerous (and not just tricky w.r.t. before and after
super), I would vote for leaving the callbacks as they are.
On Jul 24, 6:40 am, "Piers Cawley" <[EMAIL PROTECTED]> wrote:
> On 24/07/07, Ben Munat <[EMAIL PROTECTED]> wrote:
>
> > So, Piers, you're the one that started this whole thing... if it really is
> > safe to do:
>
> > class MyModel < ActiveRecord::Base
> > def initialize(attrs = {}, &block)
> > super
> > # all my initialization stuff here
> > end
> > end
>
> > and this is documented in the AR::Base docs, then this does kind of seem
> > like enough. I mean, it's
> > what I did all the time in my java life.
>
> > I'd just swear that someone told me the holy beasts of doom would swarm
> > down upon me if I ever tried
> > to override AR::Base#initialize.
>
> Yeah, I think I've heard the Holy Beasts of Doom argument as well, I
> just can't for the life of me remember where. I have certainly been
> bitten by trying to set the defaults before calling super though
> (because, dammit, that's the logical place to set defaults). Thinking
> about it, the way to do that would be something like:
>
> def initialize(attrs = {}, &block)
> super attrs.reverse_merge(:default => 'this'), &block
> end
>
> but then you make yourself a hostage to fortune that everyone's going
> to use symbols as keys. The post super approach to setting defaults
> has some edge case problems too in cases where nil is a legal value
> for some attribute (yeah, it's a weird edge case, but an edge case all
> the same). You end up with ugly code like:
>
> def initialize(attrs = {}, &block)
> super
> unless attrs.has_key?(:content) || attrs.has_key?('content')
> self.content = "Write something here"
> end
> end
>
> The issue is, I think, that ActiveRecord::Base#initialize is doing two
> different 'sorts' of things: class invariant metadata initialization,
> and instance specific initialization. You might compose the method as:
>
> def initialize(attributes = nil, &block)
> initialize_metadata
> initialize_instance(attributes, &block)
> end
>
> def initialize_metadata
> @attributes = attributes_from_column_definition
> @new_record = true
> ensure_proper_type
> end
>
> def initialize_instance(attributes
> self.attributes = attributes unless attributes.nil?
> yield self if block_given?
> end
>
> Maybe the right thing to do is to implement ActiveRecord::Base.new as:
>
> class ActiveRecord::Base
> def self.new(attributes = nil, &block)
> returning(self.allocate) do |instance|
> instance.initialize_metadata
> instance.initialize(attributes, &block)
> end
> end
>
> def initialize_metadata
> @attributes = attributes_from_column_definition
> @new_record = true
> ensure_proper_type
> end
>
> def initialize(attributes)
> self.attributes = attributes unless attributes.nil?
> yield self if block_given?
> end
> end
>
> Then anyone who wants to write code that initializes defaults before
> the actual attributes are set can do:
>
> def initialize(attributes = nil, &block)
> self.content = "Write something here"
> super
> end
>
> and everybody is happy.
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "Ruby
on Rails: Core" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at
http://groups.google.com/group/rubyonrails-core?hl=en
-~----------~----~----~----~------~----~------~--~---