Nil can't be coerced into BigDecimal

hi guys im playing with RoR with the environment of rails 3 ruby 1.9 i
got stuck in

nil can’t be coerced into BigDecimal

error

i need to get the total cost of the products inside the cart i know
where the problem is(i think) but i almost did every thing
cart/show.html.rb

Your Cart
<% for item in @cart.line_items %> <% end %>
<%= item.quantity %>× <%= item.product.title %> <%= number_to_currency(item.total_price) %>
Total <%= number_to_currency(@cart.total_price) %>
<%= button_to 'Empty cart', @cart, :method => :delete, :confirm => 'Are you sure?' %>

model/line_item.rb

def total_price
line_items.to_a.sum { |item| item.total_price }
end
model/cart.rb

def total_price
product.price * quantity
end
my second option is

def total_price
if product.price
product.price * quantity
else
product.price = “0.0”.to_d
end
end
but still this wont work

thanks more power to us!

On Tue, Feb 21, 2012 at 8:15 AM, LED [email protected] wrote:

   <tr class="total_line" >

def total_price
if product.price
product.price * quantity
else
product.price = “0.0”.to_d

This code is assigning a 0 to fixed price of a product
(most probably not what is intended). Probably simply
return a 0 (in BigDecimal) here.

end

end
but still this wont work

Is there a business rule that each item must realistically have
a quantity and product (and that product must have a price) ?

In that case I suggest:

  • add validations for the presence of these values
    (presence of quantity and product on item
    presence of price on product)

  • write code like:

def total_price
if self.valid?
product.price * quantity
else
0.to_d
end
end

Another possible gotcha is that “item.product_id” is available
(e.g. from a select box), but item.product is not yet associated
(you may need to override the product_id= setter for that e.g.

def product_id=(product_id)
self.product = Product.find_by_id(product_id)
super
end

HTH,

Peter


*** Available for a new project ***

Peter V.
http://twitter.com/peter_v
http://rails.vandenabeele.com
http://coderwall.com/peter_v

Is there a business rule that each item must realistically have
a quantity and product (and that product must have a price) ?

uhm im following agile web development rails actualy the snippets are
from the book

  • add validations for the presence of these values
    (presence of quantity and product on item
    presence of price on product)
    i already validated the price
    of each item in CRUD

model/product.rb
validates :price, :numericality => {:greater_than_or_equal_to =>
0.01}

im trying to to follow your suggestion but nothing happens it was
still the same as it was :frowning:

yes those data are valid actualy a while ago it worked but when i
clear and destroy the cart it returned to this error
very much appreciated for your effort thank you

On Tue, Feb 21, 2012 at 9:48 AM, LED [email protected] wrote:

i already validated the price
of each item in CRUD

model/product.rb
validates :price, :numericality => {:greater_than_or_equal_to =>
0.01}

For clarity. It is not because a validation is present that the
value is always present in memory (in the database, using the
standard techniques for saving, only valid data should ever be
really saved).

Is the data for the item valid?

  • quantity
  • product
  • product_id

Check out the values of those 3.

HTH,

Peter

On 21.02.2012, at 11:15, LED wrote:

hi guys im playing with RoR with the environment of rails 3 ruby 1.9 i
got stuck in

nil can’t be coerced into BigDecimal

def total_price
line_items.to_a.sum { |item| item.total_price }
end
model/cart.rb

That error would be expected when some of line_items.total_price returns
nil. Moreover you can sum total prices without .to_a, that would be more
efficient.

def total_price
product.price * quantity
end

def total_price
if product.price
product.price * quantity
else
product.price = “0.0”.to_d
It is not necessary to write attribute :price, just let it return
zero. 0.to_d in this case.

end

end

Now. before test it again, check in the database if any product has a
nil or any non-bigdecimal value.

nil can’t be coerced into BigDecimal

def total_price
line_items.to_a.sum { |item| item.total_price }
end
model/cart.rb

That error would be expected when some of line_items.total_price returns
nil. Moreover you can sum total prices without .to_a, that would be more
efficient.
tried to applying this but gotting the problem in the view

def total_price
product.price * quantity
end

def total_price
if product.price
product.price * quantity
else
product.price = “0.0”.to_d
It is not necessary to write attribute :price, just let it return
zero. 0.to_d in this case.
i tried this and it worked out but when reseting the cart it return the
error

end

end
Now. before test it again, check in the database if any product has a
nil or any non-bigdecimal value.

this is being weird when i tried your suggestion it worked out but when
i
clear delete the cart again it return to the error :frowning:

app/models/line_item.rb:24:in *' app/models/line_item.rb:24:intotal_price’
app/views/carts/show.html.erb:7:in block in _app_views_carts_show_html_erb___389431939__618846538' activerecord (3.1.1) lib/active_record/associations/collection_proxy.rb:91:ineach’
activerecord (3.1.1)
lib/active_record/associations/collection_proxy.rb:91:in
method_missing' app/views/carts/show.html.erb:3:in_app_views_carts_show_html_erb___389431939__618846538’
actionpack (3.1.1) lib/action_view/template.rb:144:in block in render' activesupport (3.1.1) lib/active_support/notifications.rb:55:ininstrument’
actionpack (3.1.1) lib/action_view/template.rb:142:in render' actionpack (3.1.1) lib/action_view/renderer/template_renderer.rb:40:inblock (2 levels) in render_template’
actionpack (3.1.1) lib/action_view/renderer/abstract_renderer.rb:33:in
block in instrument' activesupport (3.1.1) lib/active_support/notifications.rb:53:inblock
in instrument’
activesupport (3.1.1)
lib/active_support/notifications/instrumenter.rb:21:in instrument' activesupport (3.1.1) lib/active_support/notifications.rb:53:ininstrument’
actionpack (3.1.1) lib/action_view/renderer/abstract_renderer.rb:33:in
instrument' actionpack (3.1.1) lib/action_view/renderer/template_renderer.rb:39:inblock in render_template’
actionpack (3.1.1) lib/action_view/renderer/template_renderer.rb:47:in
render_with_layout' actionpack (3.1.1) lib/action_view/renderer/template_renderer.rb:38:inrender_template’
actionpack (3.1.1) lib/action_view/renderer/template_renderer.rb:12:in
block in render' actionpack (3.1.1) lib/action_view/renderer/abstract_renderer.rb:22:inwrap_formats’
actionpack (3.1.1) lib/action_view/renderer/template_renderer.rb:9:in
render' actionpack (3.1.1) lib/action_view/renderer/renderer.rb:36:inrender_template’
actionpack (3.1.1) lib/action_view/renderer/renderer.rb:17:in render' actionpack (3.1.1) lib/abstract_controller/rendering.rb:120:in_render_template’
actionpack (3.1.1) lib/action_controller/metal/streaming.rb:250:in
_render_template' actionpack (3.1.1) lib/abstract_controller/rendering.rb:114:inrender_to_body’
actionpack (3.1.1) lib/action_controller/metal/renderers.rb:30:in
render_to_body' actionpack (3.1.1) lib/action_controller/metal/compatibility.rb:43:inrender_to_body’
actionpack (3.1.1) lib/abstract_controller/rendering.rb:99:in render' actionpack (3.1.1) lib/action_controller/metal/rendering.rb:16:inrender’
actionpack (3.1.1) lib/action_controller/metal/instrumentation.rb:40:in
block (2 levels) in render' activesupport (3.1.1) lib/active_support/core_ext/benchmark.rb:5:inblock in ms’
/home/led/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/benchmark.rb:310:in
realtime' activesupport (3.1.1) lib/active_support/core_ext/benchmark.rb:5:inms’
actionpack (3.1.1) lib/action_controller/metal/instrumentation.rb:40:in
block in render' actionpack (3.1.1) lib/action_controller/metal/instrumentation.rb:78:incleanup_view_runtime’
activerecord (3.1.1)
lib/active_record/railties/controller_runtime.rb:24:in
cleanup_view_runtime' actionpack (3.1.1) lib/action_controller/metal/instrumentation.rb:39:inrender’
actionpack (3.1.1) lib/action_controller/metal/implicit_render.rb:10:in
default_render' actionpack (3.1.1) lib/action_controller/metal/mime_responds.rb:268:inblock in retrieve_response_from_mimes’
actionpack (3.1.1) lib/action_controller/metal/mime_responds.rb:195:in
call' actionpack (3.1.1) lib/action_controller/metal/mime_responds.rb:195:inrespond_to’
app/controllers/carts_controller.rb:22:in show' actionpack (3.1.1) lib/action_controller/metal/implicit_render.rb:4:insend_action’
actionpack (3.1.1) lib/abstract_controller/base.rb:167:in
process_action' actionpack (3.1.1) lib/action_controller/metal/rendering.rb:10:inprocess_action’
actionpack (3.1.1) lib/abstract_controller/callbacks.rb:18:in block in process_action' activesupport (3.1.1) lib/active_support/callbacks.rb:416:in_run__371692982__process_action__266900328__callbacks’
activesupport (3.1.1) lib/active_support/callbacks.rb:386:in
_run_process_action_callbacks' activesupport (3.1.1) lib/active_support/callbacks.rb:81:inrun_callbacks’
actionpack (3.1.1) lib/abstract_controller/callbacks.rb:17:in
process_action' actionpack (3.1.1) lib/action_controller/metal/rescue.rb:17:inprocess_action’
actionpack (3.1.1) lib/action_controller/metal/instrumentation.rb:30:in
block in process_action' activesupport (3.1.1) lib/active_support/notifications.rb:53:inblock
in instrument’
activesupport (3.1.1)
lib/active_support/notifications/instrumenter.rb:21:in instrument' activesupport (3.1.1) lib/active_support/notifications.rb:53:ininstrument’
actionpack (3.1.1) lib/action_controller/metal/instrumentation.rb:29:in
process_action' actionpack (3.1.1) lib/action_controller/metal/params_wrapper.rb:201:inprocess_action’
activerecord (3.1.1)
lib/active_record/railties/controller_runtime.rb:18:in process_action' actionpack (3.1.1) lib/abstract_controller/base.rb:121:inprocess’
actionpack (3.1.1) lib/abstract_controller/rendering.rb:45:in process' actionpack (3.1.1) lib/action_controller/metal.rb:193:indispatch’
actionpack (3.1.1) lib/action_controller/metal/rack_delegation.rb:14:in
dispatch' actionpack (3.1.1) lib/action_controller/metal.rb:236:inblock in
action’
actionpack (3.1.1) lib/action_dispatch/routing/route_set.rb:65:in call' actionpack (3.1.1) lib/action_dispatch/routing/route_set.rb:65:indispatch’
actionpack (3.1.1) lib/action_dispatch/routing/route_set.rb:29:in call' rack-mount (0.8.3) lib/rack/mount/route_set.rb:152:inblock in call’
rack-mount (0.8.3) lib/rack/mount/code_generation.rb:96:in block in recognize' rack-mount (0.8.3) lib/rack/mount/code_generation.rb:96:inoptimized_each’
rack-mount (0.8.3) lib/rack/mount/code_generation.rb:95:in recognize' rack-mount (0.8.3) lib/rack/mount/route_set.rb:141:incall’
actionpack (3.1.1) lib/action_dispatch/routing/route_set.rb:532:in
call' actionpack (3.1.1) lib/action_dispatch/middleware/best_standards_support.rb:17:incall’
rack (1.3.6) lib/rack/etag.rb:23:in call' rack (1.3.6) lib/rack/conditionalget.rb:25:incall’
actionpack (3.1.1) lib/action_dispatch/middleware/head.rb:14:in call' actionpack (3.1.1) lib/action_dispatch/middleware/params_parser.rb:21:incall’
actionpack (3.1.1) lib/action_dispatch/middleware/flash.rb:243:in call' rack (1.3.6) lib/rack/session/abstract/id.rb:195:incontext’
rack (1.3.6) lib/rack/session/abstract/id.rb:190:in call' actionpack (3.1.1) lib/action_dispatch/middleware/cookies.rb:331:incall’
activerecord (3.1.1) lib/active_record/query_cache.rb:62:in call' activerecord (3.1.1) lib/active_record/connection_adapters/abstract/connection_pool.rb:477:incall’
actionpack (3.1.1) lib/action_dispatch/middleware/callbacks.rb:29:in
block in call' activesupport (3.1.1) lib/active_support/callbacks.rb:392:in_run_call_callbacks’
activesupport (3.1.1) lib/active_support/callbacks.rb:81:in
run_callbacks' actionpack (3.1.1) lib/action_dispatch/middleware/callbacks.rb:28:incall’
actionpack (3.1.1) lib/action_dispatch/middleware/reloader.rb:68:in
call' rack (1.3.6) lib/rack/sendfile.rb:101:incall’
actionpack (3.1.1) lib/action_dispatch/middleware/remote_ip.rb:48:in
call' actionpack (3.1.1) lib/action_dispatch/middleware/show_exceptions.rb:47:incall’
railties (3.1.1) lib/rails/rack/logger.rb:13:in call' rack (1.3.6) lib/rack/methodoverride.rb:24:incall’
rack (1.3.6) lib/rack/runtime.rb:17:in call' activesupport (3.1.1) lib/active_support/cache/strategy/local_cache.rb:72:incall’
rack (1.3.6) lib/rack/lock.rb:15:in call' actionpack (3.1.1) lib/action_dispatch/middleware/static.rb:53:incall’
railties (3.1.1) lib/rails/engine.rb:456:in call' railties (3.1.1) lib/rails/rack/content_length.rb:16:incall’
railties (3.1.1) lib/rails/rack/log_tailer.rb:14:in call' rack (1.3.6) lib/rack/handler/webrick.rb:59:inservice’
/home/led/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/webrick/httpserver.rb:111:in
service' /home/led/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/webrick/httpserver.rb:70:inrun’
/home/led/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/webrick/server.rb:183:in
`block in start_thread’

its the full trace of the error cant seems to find it im a week old in
ruby on rails development

I didn’t see you code completely, but

line_items.to_a.sum { |item| item.total_price }

How can it count correct if only ONE item in the cart? :slight_smile:

Obviously, if you want to get Array, use Array.wrap method like this:

Array.wrap(line_items).sum { |item| item.total_price }

i tried refactoring my destroy method now its working fine but my second
issue is when i add item to the cart at first attemp it returns to that
error again but returning to the product list it worked fine im just
wondering if my add_product is code is ok?

def add_product(product_id)
current_item = line_items.where(:product_id => product_id).first

 if current_item
    current_item.quantity = current_item.quantity.to_i + 1
  else
    current_item = LineItem.new(:product_id=>product_id)
    line_items << current_item
  end
    current_item

end

Valery K. wrote in post #1047975:

I didn’t see you code completely, but

line_items.to_a.sum { |item| item.total_price }

How can it count correct if only ONE item in the cart? :slight_smile:

Obviously, if you want to get Array, use Array.wrap method like this:

Array.wrap(line_items).sum { |item| item.total_price }

i tried Array.wrap(line_items).sum { |item| item.total_price }
also it worked same as the
line_items.to_a.sum { |item| item.total_price }
(i think?)
but im having the issue of not counting my first attemp of adding
product in to the cart, but return to home and clicking it second time
it work but didnt count my first attemp of adding a product maybe my
add_product code is wrong?

def add_product(product_id)
current_item = line_items.where(:product_id => product_id).first

 if current_item
    current_item.quantity = current_item.quantity.to_i + 1
  else
    current_item = LineItem.new(:product_id=>product_id)
    line_items << current_item
  end
    current_item

end

it feels like im adding a nil value at my first attemp of adding a
product into my cart?
btw thanks for your concern with my post :slight_smile:

def add_product(product_id)
current_item = line_items.where(:product_id => product_id).first

if current_item
   current_item.quantity = current_item.quantity.to_i + 1
 else
   current_item = LineItem.new(:product_id=>product_id)
   line_items << current_item

Ok, let’s imagine. You add new LineItem and product.price is nil or
quantity is nil
then
product.price * quantity
would raise error “nil can’t be coerced into”

Check if product price or quantity is nil after initialize
LineItem.new

Colin L. wrote in post #1047978:

On 21 February 2012 09:39, ruby LED [email protected] wrote:

it feels like im adding a nil value at my first attemp of adding a
product into my cart?

It is not the item that is nil but total_price. If it were the item
that were nil then you would get an error saying that nil did not have
a method total_price. Where are you setting total_price when you do
LineItem.new.

i belive im setting it in the current_item it self
current_item = LineItem.new(:product_id=>product_id)

Colin

Show us the code of LineItem class.

This method raises the error on a new instance. To avoid it, it must
return BigDec anytime. In your case product.price is nil or quantity is
nil…

def total_price
product.price * quantity
end

On 21 February 2012 09:39, ruby LED [email protected] wrote:

if current_item
current_item.quantity = current_item.quantity.to_i + 1
else
current_item = LineItem.new(:product_id=>product_id)
line_items << current_item
end
current_item
end

it feels like im adding a nil value at my first attemp of adding a
product into my cart?

It is not the item that is nil but total_price. If it were the item
that were nil then you would get an error saying that nil did not have
a method total_price. Where are you setting total_price when you do
LineItem.new.

Colin

On Tue, Feb 21, 2012 at 10:55 AM, ruby LED [email protected] wrote:

i belive im setting it in the current_item it self
current_item = LineItem.new(:product_id=>product_id)

As I wrote above. This sets the product_id, but not
necessarily the “product” association. Check values of

  • current_item.product_id
  • current_item.product
    right after this line.

HTH,

Peter

Valery K. wrote in post #1047982:

Show us the code of LineItem class.

This method raises the error on a new instance. To avoid it, it must
return BigDec anytime. In your case product.price is nil or quantity is
nil…

def total_price
product.price * quantity
end

class LineItem < ActiveRecord::Base
belongs_to :product
belongs_to :cart

def total_price
if product.price
product.price = product.price * quantity
else
0.to_d
end
end
end

this is my model/line item.rb

On 21.02.2012, at 14:08, ruby LED wrote:

end
end

So.

I agree that:

  1. current_item = LineItem.new(:product_id=>product_id) = BAD IDEA.
    Because, if you pass the invalid product ID, LineItem would be
    initialized as well, but the .product association would return nil.

  2. Actually I didn’t see how quantity is set up? Looking at your
    previous code it must be method ‘quantity’.

PS. Why are you writing product.price=?

Valery K. wrote in post #1047990:

On 21.02.2012, at 14:08, ruby LED wrote:

end
end

So.

I agree that:

  1. current_item = LineItem.new(:product_id=>product_id) = BAD IDEA.
    Because, if you pass the invalid product ID, LineItem would be
    initialized as well, but the .product association would return nil.
    do you think current_item = line_items.build(:product_id => product_id)
    is better?
  2. Actually I didn’t see how quantity is set up? Looking at your
    previous code it must be method ‘quantity’.
    i dont have a method quantity
    PS. Why are you writing product.price=?
    i belive it is same with product.price * quantity
    to show the sum of all products inside my cart

PS. Why are you writing product.price=?
i belive it is same with product.price * quantity
to show the sum of all products inside my cart

Logic, logic, logic.

product - is a stand alone instance or One product. Why Would it ever
have the multiplied price with ‘quantity’ ?.

I remember many years ago I read the beginner’s book “Agile Web
Development with Rails”, is that example from it? I think you missed
something.
thank very much for the effort yes this is from the book agile web
development with rails sorry about it im just starting to learn ruby on
rails