Piers Cawley 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.
>
+1 for everybody.
Largely the case is simply setting defaults with "if new_record?". Since
it's 80% of the job that can be handled with (ficitional) 20% code such as:
def after_new_record
country = 'United States'
is_administrator? = false
end
I think that's nice :) (since it doesn't use a dynamic trigger, it
should pose not very big overhead?)
--
Hendy Irawan
www.hendyirawan.com
--~--~---------~--~----~------------~-------~--~----~
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
-~----------~----~----~----~------~----~------~--~---