I have a new app (Rails 2.3.8) that uses lots of money fields. I'm
using the money gem (3.0.5) and the acts_as_money plugin. I've written
a number of rspec model examples and everything seems to be working
fine there.
My problem is in defining forms for new & edit. As I've done in past
projects for complex layouts, I extracted the basic form to a partial
and include it in the new & edit views.
However, the model object is created and left with nulls in the
fields, and causes the money gem to complain with:
"undefined method `subunit_to_unit' for nil:NilClass".
I thought I could use something like after_initialize() to hook into
the creation of a new object in Rails and set all the money attributes
to zero, but that didn't work (and several posts recommended against
that for performance reasons)...
Any suggestions on a clean way to hook my model object and make sure
it's got zeros for all the money values when the new object is
instantiated?
I have a new app (Rails 2.3.8) that uses lots of money fields. I'm
using the money gem (3.0.5) and the acts_as_money plugin. I've written
a number of rspec model examples and everything seems to be working
fine there.
My problem is in defining forms for new & edit. As I've done in past
projects for complex layouts, I extracted the basic form to a partial
and include it in the new & edit views.
However, the model object is created and left with nulls in the
fields, and causes the money gem to complain with:
"undefined method `subunit_to_unit' for nil:NilClass".
I thought I could use something like after_initialize() to hook into
the creation of a new object in Rails and set all the money attributes
to zero, but that didn't work (and several posts recommended against
that for performance reasons)...
Any suggestions on a clean way to hook my model object and make sure
it's got zeros for all the money values when the new object is
instantiated?
Why not define a default value for the field on the DB side? This has
the added advantage of ensuring that there is no way to accidentally
create a record without these values even if the Rails app is bypassed.
I've done all that; but since this is an ActiveRecord object, I was
hoping there was a way to do this in one spot, through a Rails hook,
rather than having to remember to code this each time.
The way I encapsulated all this was to create an initialize_to_zeros
method and now I call that each time after doing a model.new
It would be more helpful to me if you were to actually describe what
you are talking about.
If what you are saying is "override initialize" like so:
<pre>
Class Recipe < ActiveRecord::Base
def initialize (name, yield_amount, yield_unit)
self.unit_type = get_unit_type(yield_unit)
self.name = name
self.yield_amount = yield_amount
self.yield_unit = yield_unit
end
end
<pre/>
that's not a good idea. All the posts I have read recommend against
this because Active Record doesn't always use initialize when creating
new instances.
If what you are saying is "add parameters to new, like so (or with a
hash):
<pre>
user = User.new(:name => "David", :occupation => "Code Artist")
<pre/>
that's exactly what I want to avoid having to do every time I create a
new instance.
If there's another approach that I don't know about, I'm all ears.
It would be more helpful to me if you were to actually describe what
you are talking about.
I did. If you don't know what a constructor is, then you need to review
your basic Ruby in order to use Rails effectively.
If what you are saying is "override initialize"
That is basically what I am saying, but you should start the overridden
initializer by calling super.
like so:
<pre>
Class Recipe < ActiveRecord::Base
def initialize (name, yield_amount, yield_unit)
self.unit_type = get_unit_type(yield_unit)
self.name = name
self.yield_amount = yield_amount
self.yield_unit = yield_unit
end
end
<pre/>
that's not a good idea. All the posts I have read recommend against
this because Active Record doesn't always use initialize when creating
new instances.
I'm not sure that's still true, but if it is, then you can use the
after_initialize or after_create callbacks.
If what you are saying is "add parameters to new, like so (or with a
hash):
<pre>
user = User.new(:name => "David", :occupation => "Code Artist")
<pre/>
that's exactly what I want to avoid having to do every time I create a
new instance.
I know.
If there's another approach that I don't know about, I'm all ears.
Anyway, as I mentioned before, after_create is way too late in the
sequence of things to do any good and after_initialize is recommended
against (as is after_find) because of performance reasons.
I believe I know what a constructor is, so your snide comments
continue to be of no help.
Please quote when replying! It's impossible to follow the discussion if
you don't.
Jon Seidel wrote:
Sorry, Marnen...
Anyway, as I mentioned before, after_create is way too late in the
sequence of things to do any good and after_initialize is recommended
against (as is after_find) because of performance reasons.
Only because it's called for each object. In this case, that's exactly
what you need, so use it. The docs seem to say that you shouldn't be
using it *if you don't need to*, but in this case you need to.
Don't reject the purpose-made solution that's right in front of your
face.
I believe I know what a constructor is, so your snide comments
continue to be of no help.
Snide comments? Sorry, that's not at all what I meant. You seemed not
to know, so I was trying to encourage you to find out.
I'll look elsewhere...thanks...jon
No need to look elsewhere. after_initialize is what you need.
No point to look elsewhere. Nothing else will do the trick.