Can anybody share some examples of their Money implementation ? I''m trying to setup a Model to use this library, but can''t seem to wrap my head around how it is exactly supposed to work. My Model (Foo) looks like: ==============composed_of :commission, :class_name => "Money", :mapping => [ %w(commission_cents cents), %w(commission_currency currency) ] Yet, in script/console, I''m unable to get the correct behaviour (at least I think), from the library. ==============>> t = Foo.new(:commission => 34) NoMethodError: undefined method `cents'' for 34:Fixnum from (eval):3:in `commission='' I''ve tried just playing with the Money object as well, but regardless of what number I pass into the Money constructor, it always provides me with the exact number I specify as the "cents" value. So, If I do: Money.new( 34.43)... it tells me that the instance has 34 cents. I must be overlooking something. Any insight would be greatly appreciated ! -------------- next part -------------- An HTML attachment was scrubbed... URL: http://wrath.rubyonrails.org/pipermail/rails/attachments/20060228/01ed4e9a/attachment.html
On Feb 27, 2006, at 5:06 PM, Dylan Stamat wrote:> Can anybody share some examples of their Money implementation ? > > I''m trying to setup a Model to use this library, but can''t seem to > wrap my head around how it is exactly supposed to work. > My Model (Foo) looks like: > ==============> composed_of :commission, :class_name => "Money", :mapping => [ %w > (commission_cents cents), %w(commission_currency currency) ] > > Yet, in script/console, I''m unable to get the correct behaviour (at > least I think), from the library. > ==============> >> t = Foo.new(:commission => 34) > NoMethodError: undefined method `cents'' for 34:Fixnum > from (eval):3:in `commission=''Try: t = Foo.new(:commission => Money.new(34)) or t=Foo.new t.commission = Money.new(34) -- -- Tom Mornini
Hey Tom ! That does work... and after looking at the actual source, it does initialize with only cents. So, that means that I probably need to instantiate a Money object in the view: <%= text_field ... etc... Money.new(myvalue) %> ...,or, for every attribute in the model that does this composed_of: def commission=(commission) Money.new(commission) end Is this the correct approach ?... or am I missing something ? If this is correct, it would be great to add some of this to the docs ! On 2/27/06, Tom Mornini <tmornini@infomania.com> wrote:> > On Feb 27, 2006, at 5:06 PM, Dylan Stamat wrote: > > > Can anybody share some examples of their Money implementation ? > > > > I''m trying to setup a Model to use this library, but can''t seem to > > wrap my head around how it is exactly supposed to work. > > My Model (Foo) looks like: > > ==============> > composed_of :commission, :class_name => "Money", :mapping => [ %w > > (commission_cents cents), %w(commission_currency currency) ] > > > > Yet, in script/console, I''m unable to get the correct behaviour (at > > least I think), from the library. > > ==============> > >> t = Foo.new(:commission => 34) > > NoMethodError: undefined method `cents'' for 34:Fixnum > > from (eval):3:in `commission='' > > Try: > t = Foo.new(:commission => Money.new(34)) > > or > > t=Foo.new > t.commission = Money.new(34) > > -- > -- Tom Mornini > > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails >-------------- next part -------------- An HTML attachment was scrubbed... URL: http://wrath.rubyonrails.org/pipermail/rails/attachments/20060228/fd2714ae/attachment-0001.html
On Feb 27, 2006, at 8:35 PM, Dylan Stamat wrote:> Hey Tom ! That does work... and after looking at the actual > source, it does > initialize with only cents. So, that means that I probably need to > instantiate > a Money object in the view: > <%= text_field ... etc... Money.new (myvalue) %>No, that should be totally unnecessary. Creating objects in a view is a bad practice in any case... Get the money value into a non-db backed attribute...or the cents attribute since it''s already around, then, upon form handling in the controller: object = Object.new(params[:object]) object.commission = Money.new(object.cents) The bottom line is this: when using composed_of, you must assign to it with an object of the same class of the composed_of, which makes sense when you think about it...> ...,or, for every attribute in the model that does this composed_of: > def commission=(commission) > Money.new(commission) > endThat''s cute! I sort of like it, but I doubt it''s what you really want, as it will likely break the composed_of wizardly that allows you to set the composed_of object in the first place... Perhaps you could name it: def set_commission(cents,currency=''USD'') commision = Money.new(cents,currency) end Note the use of currency, and default of ''USD'' (my favorite currency, but perhaps not yours, and perhaps not the best choice for your application). No reason to go through the work of implementing Money (a good idea!) and not wire it up so you can use the multi-currency functionality without a lot of work later! -- -- Tom Mornini
Great points Tom... and I am desperately trying to make my code less cute :) So, then there is no way I can just "create" the object when using composed_of ? model = MyModel.create(params[:mymodel]) So in my example, my Term model would actually need a non-model "Commission" value object lying around ? On 2/27/06, Tom Mornini <tmornini@infomania.com> wrote:> > On Feb 27, 2006, at 8:35 PM, Dylan Stamat wrote: > > > Hey Tom ! That does work... and after looking at the actual > > source, it does > > initialize with only cents. So, that means that I probably need to > > instantiate > > a Money object in the view: > > <%= text_field ... etc... Money.new (myvalue) %> > > No, that should be totally unnecessary. Creating objects in a view is > a bad > practice in any case... > > Get the money value into a non-db backed attribute...or the cents > attribute > since it''s already around, then, upon form handling in the controller: > > object = Object.new(params[:object]) > object.commission = Money.new(object.cents) > > The bottom line is this: when using composed_of, you must assign to it > with an object of the same class of the composed_of, which makes sense > when you think about it... > > > ...,or, for every attribute in the model that does this composed_of: > > def commission=(commission) > > Money.new(commission) > > end > > That''s cute! I sort of like it, but I doubt it''s what you really > want, as > it will likely break the composed_of wizardly that allows you to set the > composed_of object in the first place... Perhaps you could name it: > > def set_commission(cents,currency=''USD'') > commision = Money.new(cents,currency) > end > > Note the use of currency, and default of ''USD'' (my favorite currency, > but > perhaps not yours, and perhaps not the best choice for your > application). > No reason to go through the work of implementing Money (a good idea!) > and > not wire it up so you can use the multi-currency functionality without a > lot of work later! > > -- > -- Tom Mornini > > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails >-------------- next part -------------- An HTML attachment was scrubbed... URL: http://wrath.rubyonrails.org/pipermail/rails/attachments/20060228/1000a7e3/attachment.html
On Feb 27, 2006, at 11:11 PM, Dylan Stamat wrote:> So, then there is no way I can just "create" the object when using > composed_of ? > model = MyModel. create(params[:mymodel])Maybe not...you might well be able to set up something like in MyModel...it''s your idea, after all! This code is untested... # can a default be an attribute and/or method call? def commission_cents=(cents,currency=self.currency) self.commission = Money.new(cents,currency) end And in the form: <%= text_field ''Commission'', :mymodel, :commission_cents %> -- -- Tom Mornini -------------- next part -------------- An HTML attachment was scrubbed... URL: http://wrath.rubyonrails.org/pipermail/rails/attachments/20060228/6496903b/attachment.html
On 2/28/06, Tom Mornini <tmornini@infomania.com> wrote:> > On Feb 27, 2006, at 11:11 PM, Dylan Stamat wrote: > So, then there is no way I can just "create" the object when using > composed_of ? > model = MyModel. create(params[:mymodel]) > > Maybe not...you might well be able to set up something like in > MyModel...it''s > your idea, after all! This code is untested... > > # can a default be an attribute and/or method call? > > def commission_cents=(cents,currency=self.currency) > self.commission = Money.new(cents,currency) > end > > And in the form: > > <%= text_field ''Commission'', :mymodel, :commission_cents %> >Hm, here''s what I have: class Product composed_of :price, :class_name => Money, :mapping => [[:price, :cents]] # other stuff end When I do (in my unit tests) p = Product.create I get: NoMethodError: You have a nil object when you didn''t expect it! The error occured while evaluating nil.round from /usr/lib/ruby/gems/1.8/gems/money-1.7.1/lib/money/money.rb:52:in `initialize'' from (eval):3:in `price'' Any ideas?
I''m pretty sure you cannot reuse the DB column name for the composed_of value object. -- -- Tom Mornini On Feb 28, 2006, at 1:09 AM, Joe Van Dyk wrote:> On 2/28/06, Tom Mornini <tmornini@infomania.com> wrote: >> >> On Feb 27, 2006, at 11:11 PM, Dylan Stamat wrote: >> So, then there is no way I can just "create" the object when using >> composed_of ? >> model = MyModel. create(params[:mymodel]) >> >> Maybe not...you might well be able to set up something like in >> MyModel...it''s >> your idea, after all! This code is untested... >> >> # can a default be an attribute and/or method call? >> >> def commission_cents=(cents,currency=self.currency) >> self.commission = Money.new(cents,currency) >> end >> >> And in the form: >> >> <%= text_field ''Commission'', :mymodel, :commission_cents %> >> > > Hm, here''s what I have: > > class Product > composed_of :price, :class_name => Money, :mapping => > [[:price, :cents]] > # other stuff > end > > When I do (in my unit tests) > p = Product.create > I get: > NoMethodError: You have a nil object when you didn''t expect it! > The error occured while evaluating nil.round > from /usr/lib/ruby/gems/1.8/gems/money-1.7.1/lib/money/ > money.rb:52:in > `initialize'' > from (eval):3:in `price'' > > Any ideas? > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails
your cents column needs to default to zero On 2/28/06, Joe Van Dyk <joevandyk@gmail.com> wrote:> On 2/28/06, Tom Mornini <tmornini@infomania.com> wrote: > > > > On Feb 27, 2006, at 11:11 PM, Dylan Stamat wrote: > > So, then there is no way I can just "create" the object when using > > composed_of ? > > model = MyModel. create(params[:mymodel]) > > > > Maybe not...you might well be able to set up something like in > > MyModel...it''s > > your idea, after all! This code is untested... > > > > # can a default be an attribute and/or method call? > > > > def commission_cents=(cents,currency=self.currency) > > self.commission = Money.new(cents,currency) > > end > > > > And in the form: > > > > <%= text_field ''Commission'', :mymodel, :commission_cents %> > > > > Hm, here''s what I have: > > class Product > composed_of :price, :class_name => Money, :mapping => [[:price, :cents]] > # other stuff > end > > When I do (in my unit tests) > p = Product.create > I get: > NoMethodError: You have a nil object when you didn''t expect it! > The error occured while evaluating nil.round > from /usr/lib/ruby/gems/1.8/gems/money-1.7.1/lib/money/money.rb:52:in > `initialize'' > from (eval):3:in `price'' > > Any ideas? > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails >-- Tobi http://shopify.com - modern e-commerce software http://typo.leetsoft.com - Open source weblog engine http://blog.leetsoft.com - Technical weblog
Are you running money 1.7.0 ? On 2/27/06, Dylan Stamat <dylans@gmail.com> wrote:> Can anybody share some examples of their Money implementation ? > > I''m trying to setup a Model to use this library, but can''t seem to wrap my > head around how it is exactly supposed to work. > My Model (Foo) looks like: > ==============> composed_of :commission, :class_name => "Money", :mapping => [ > %w(commission_cents cents), %w(commission_currency currency) ] > > Yet, in script/console, I''m unable to get the correct behaviour (at least I > think), from the library. > ==============> >> t = Foo.new(:commission => 34) > NoMethodError: undefined method `cents'' for 34:Fixnum > from (eval):3:in `commission='' > > > I''ve tried just playing with the Money object as well, but regardless of > what number I pass into the Money constructor, it always provides me with > the exact number I specify as the "cents" value. So, If I do: > Money.new(34.43)... it tells me that the instance has 34 cents. > > I must be overlooking something. Any insight would be greatly appreciated ! > > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails > > >-- Tobi http://shopify.com - modern e-commerce software http://typo.leetsoft.com - Open source weblog engine http://blog.leetsoft.com - Technical weblog
Thanks for popping in here Tobias :) I''m running into a similar problem as Joe, and running 1.7.1. On 2/28/06, Tobias L?tke <tobias.luetke@gmail.com> wrote:> > Are you running money 1.7.0 ? > > On 2/27/06, Dylan Stamat <dylans@gmail.com> wrote: > > Can anybody share some examples of their Money implementation ? > > > > I''m trying to setup a Model to use this library, but can''t seem to wrap > my > > head around how it is exactly supposed to work. > > My Model (Foo) looks like: > > ==============> > composed_of :commission, :class_name => "Money", :mapping => [ > > %w(commission_cents cents), %w(commission_currency currency) ] > > > > Yet, in script/console, I''m unable to get the correct behaviour (at > least I > > think), from the library. > > ==============> > >> t = Foo.new(:commission => 34) > > NoMethodError: undefined method `cents'' for 34:Fixnum > > from (eval):3:in `commission='' > > > > > > I''ve tried just playing with the Money object as well, but regardless of > > what number I pass into the Money constructor, it always provides me > with > > the exact number I specify as the "cents" value. So, If I do: > > Money.new(34.43)... it tells me that the instance has 34 cents. > > > > I must be overlooking something. Any insight would be greatly > appreciated ! > > > > _______________________________________________ > > Rails mailing list > > Rails@lists.rubyonrails.org > > http://lists.rubyonrails.org/mailman/listinfo/rails > > > > > > > > > -- > Tobi > http://shopify.com - modern e-commerce software > http://typo.leetsoft.com - Open source weblog engine > http://blog.leetsoft.com - Technical weblog > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails >-------------- next part -------------- An HTML attachment was scrubbed... URL: http://wrath.rubyonrails.org/pipermail/rails/attachments/20060228/26e2c01d/attachment-0001.html
On 2/28/06, Tobias L?tke <tobias.luetke@gmail.com> wrote:> On 2/28/06, Joe Van Dyk <joevandyk@gmail.com> wrote: > > On 2/28/06, Tom Mornini <tmornini@infomania.com> wrote: > > > > > > On Feb 27, 2006, at 11:11 PM, Dylan Stamat wrote: > > > So, then there is no way I can just "create" the object when using > > > composed_of ? > > > model = MyModel. create(params[:mymodel]) > > > > > > Maybe not...you might well be able to set up something like in > > > MyModel...it''s > > > your idea, after all! This code is untested... > > > > > > # can a default be an attribute and/or method call? > > > > > > def commission_cents=(cents,currency=self.currency) > > > self.commission = Money.new(cents,currency) > > > end > > > > > > And in the form: > > > > > > <%= text_field ''Commission'', :mymodel, :commission_cents %> > > > > > > > Hm, here''s what I have: > > > > class Product > > composed_of :price, :class_name => Money, :mapping => [[:price, :cents]] > > # other stuff > > end > > > > When I do (in my unit tests) > > p = Product.create > > I get: > > NoMethodError: You have a nil object when you didn''t expect it! > > The error occured while evaluating nil.round > > from /usr/lib/ruby/gems/1.8/gems/money-1.7.1/lib/money/money.rb:52:in > > `initialize'' > > from (eval):3:in `price'' > > > > Any ideas? > > your cents column needs to default to zeroAh, ok. I didn''t see that mentioned anywhere. I''ll try it tonight. Is it ok to have a database column in my products table called "price"? Or does it need to be "cents"?
On 2/28/06, Joe Van Dyk <joevandyk@gmail.com> wrote:> On 2/28/06, Tobias L?tke <tobias.luetke@gmail.com> wrote: > > On 2/28/06, Joe Van Dyk <joevandyk@gmail.com> wrote: > > > On 2/28/06, Tom Mornini <tmornini@infomania.com> wrote: > > > > > > > > On Feb 27, 2006, at 11:11 PM, Dylan Stamat wrote: > > > > So, then there is no way I can just "create" the object when using > > > > composed_of ? > > > > model = MyModel. create(params[:mymodel]) > > > > > > > > Maybe not...you might well be able to set up something like in > > > > MyModel...it''s > > > > your idea, after all! This code is untested... > > > > > > > > # can a default be an attribute and/or method call? > > > > > > > > def commission_cents=(cents,currency=self.currency) > > > > self.commission = Money.new(cents,currency) > > > > end > > > > > > > > And in the form: > > > > > > > > <%= text_field ''Commission'', :mymodel, :commission_cents %> > > > > > > > > > > Hm, here''s what I have: > > > > > > class Product > > > composed_of :price, :class_name => Money, :mapping => [[:price, :cents]] > > > # other stuff > > > end > > > > > > When I do (in my unit tests) > > > p = Product.create > > > I get: > > > NoMethodError: You have a nil object when you didn''t expect it! > > > The error occured while evaluating nil.round > > > from /usr/lib/ruby/gems/1.8/gems/money-1.7.1/lib/money/money.rb:52:in > > > `initialize'' > > > from (eval):3:in `price'' > > > > > > Any ideas? > > > > your cents column needs to default to zero > > Ah, ok. I didn''t see that mentioned anywhere. I''ll try it tonight. > > Is it ok to have a database column in my products table called > "price"? Or does it need to be "cents"?Yeah, I''m confused. Do I do validations on "cents" (which is now a database column in my products table) or on "price" (which is not a database column anymore)? Here''s part of my unit test for the Product class. I''m having a lot of troubles getting that to run correctly with the Money class and composed_of. def test_that_product_has_to_have_a_price_greater_than_zero p = Product.create assert p.errors.on(:price) bad_prices = %w{ 0 asdf -10 40.OO } bad_prices.each do |bad_price| p.price = bad_price p.save assert p.errors.on(:price), "<#{ bad_price}> is apparently a good price" end good_prices = %w{ 10 23.4 56.99 } good_prices.each do |price| p.price = price p.save assert_nil p.errors.on(:price) end end