views:

267

answers:

2

Hi,

I have this:

class Bullet < ActiveRecord::Base  
  include StagedVersionMethods
  ...
end

And this

module StagedVersionMethods     
  def initialize
    puts self.bullet_id
  end
end

When I create an instance of Bullet, the modules initialize method fires, but I get an ActiveRecord error: ...activerecord-2.2.2/lib/active_record/attribute_methods.rb:268:in `read_attribute'

My intent is to initialize an instance variable for which I need the primary key value of the record I'm mixing into. Other methods in the module will then work with this instance variable.

The module included() callback does not fit the task either, because self, in that context, is the Module not the AR record.

How should this be approached?

Thanks

A: 

If you define initialize like:

def initialize(*atts)
  super(*atts)
  puts self.bullet_id
end

then I think it will do what you want as it will set up the object correctly for you using the ActiveRecord initialization first. However, I'm not sure how robust that approach is for what you're trying to achieve. It might be more appropriate to create this instance variable when it is accessed rather than when the object is initialized.

It's kind of hard to say without knowing what you want the instance variable to do though.

Shadwell
Thanks Shadwell,The instance variable will be a copy of the instance "self", but with edits made to it. It's represents a temporary copy of the "parent" bullet, and the module will mix in methods to the MOdel - methods like has_temp_version?, apply_temp_version, discard_temp_version and such.I tried the approach you suggested (which makes perfect sense) however the attributes of self, including bullet_id, are all nil.I'm using your second suggestion currently and that's working fine - just a little more plumbing than I'd have liked.Cheers
Paul
+2  A: 

Overiding the initializer on ActiveRecord can have strange side effects that prove difficult to debug, so it's not recommended. The recommended approach would be to use the :after_initialize callback that ActiveRecord provides instead. You can still mix this behaviour in via a module...

module MyCleverMixin  

  def after_initialize
    puts "I'm Initializing!"
  end

end


class MyModel < ActiveRecord

  include MyCleverMixin

end
Thanks. The thing is I was expecting klass to be my Model into which I'm mixing the module, but the class of klass is "Class" and the block never gets called. Am I getting the wrong end of the stick?Thanks so much.
Paul
Actually we can simplify this just defining after_initialize in our mixin. Please take a look at my edited code above for a working example
Should that be 'include MyCleverMixin'?One other thing to note is that the after_initialize callback isn't called when you've found existing Bullets from the database. You'd need to define after_find too.
Shadwell
Perfect! Thanks so much.
Paul
Yep include not require, sorry, edited my answer above and a good point about after_find. Actually often I end up using before_create to stamp fields in my database automatically.