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
-~----------~----~----~----~------~----~------~--~---

Reply via email to