18

I am having a problem with validation errors when saving a model using save!. The ActiveRecord error model error messages are blank, so i dont know what errors are happening on a validation attempt. When I try errors.full_messages or errors.each_full according to the documentation, it should display the errors, which it doesn't.

The model I am trying to save is the Orders model (ecommerce site using Spree). When an item in the order gets deleted, update_totals! gets called which recalculates the totals, and then save! is called, which triggers the validation error (this error happens very rarely but only when I'm logged in, and I havent been able to find the cause of it). The order model has two validations in its model:

  validates_numericality_of :item_total
  validates_numericality_of :total

i recorded order.item_total.inspect, order.total.inspect, and order.errors.full_messages.inspect and got this:

Wed Jan 25 08:53:08 -0800 2012order item total: #<BigDecimal:15780c60,'0.279E2',8(16)>
Wed Jan 25 08:53:08 -0800 2012order total: #<BigDecimal:152bf410,'0.2448225E2',12(20)>
Wed Jan 25 08:53:08 -0800 2012: ERRORS SAVING ORDER: 
Wed Jan 25 08:53:08 -0800 2012[]

item_total and total are stored in the mySQL database as decimal(8,2). The last line is order.errors.full_messages.inspect, which is an empty array. The validation error looks like this:

ActiveRecord::RecordInvalid (Validation failed: {{errors}}):
  vendor/extensions/mgx_core/app/models/order.rb:382:in `update_totals!'
  vendor/extensions/mgx_core/app/controllers/line_items_controller.rb:7:in `destroy'
  app/middleware/flash_session_cookie_middleware.rb:19:in `call'
  C:\Users\mgx\My Documents\Aptana Studio 3 Workspace\catalogue-spree\script\server:3
  c:/Ruby187/lib/ruby/gems/1.8/gems/ruby-debug-ide-0.4.16/lib/ruby-debug-ide.rb:112:in `debug_load'
  c:/Ruby187/lib/ruby/gems/1.8/gems/ruby-debug-ide-0.4.16/lib/ruby-debug-ide.rb:112:in `debug_program'
  c:/Ruby187/lib/ruby/gems/1.8/gems/ruby-debug-ide-0.4.16/bin/rdebug-ide:87
  c:/Ruby187/bin/rdebug-ide:19:in `load'
  c:/Ruby187/bin/rdebug-ide:19

I guess my question is twofold:

1. Why is my activerecord errors model not saying what the validation error is?

2. How do I fix this problem? Is my item_total and total valid for saving as decimal(8,2)?

I am using rails 2.3.5 and spree 0.10.2

8
  • How are you fetching the order and line_item from the db (ie what is in your controller action)? Commented Jan 25, 2012 at 18:32
  • When a user hits the remove button in the shopping cart, it calls a function called destroy in the line_items controller. The code for destroy is: line_item = LineItem.find(params[:id], :include => :order) order = line_item.order line_item.destroy order.update_totals! update_totals! does some math to calculate new totals and then calls self.save! which triggers the validation error Commented Jan 25, 2012 at 18:36
  • Just in case here, but does the LineItem destroy the order when it is destroyed? In other words, are you sure the order itself is still valid itself before updating totals? save! should throw an exception on a validation failure, so I'd think you'd be seeing the error in your logs or whatever. Commented Jan 25, 2012 at 19:38
  • @Irongaze: the order still exists in the database and is not destroyed. Here is something odd. I am logged in with 3 items in my cart. I am in ruby console, and find the order (o = Order.find_by_number("R642608333")). o.line_items.length returns 3. o.item_total returns 28.05. All these values are true. I then delete a line item in my browser, and i get the validation error. I then call those three lines of code again. I get back o.line_items.length = 2 and o.item_total = 28.05. It seems that the order itself actually did save but the item_total value did not save. Correct total should be 27.90 Commented Jan 25, 2012 at 20:04
  • @irongaze when i check my log of what the order.item_total was RIGHT BEFORE it attempted to .save! it shows this Wed Jan 25 11:57:15 -0800 2012order item total: #<BigDecimal:1574dc78,'0.279E2',8(16)> Commented Jan 25, 2012 at 20:06

6 Answers 6

28

When you have before_validation declarations and if they return false then you'll get a Validation failed (ActiveRecord::RecordInvalid) message with an empty error message (if there are no other errors).

Note that before_validation callbacks must not return false (nil is okay) and this can happen by accident, e.g., if you are assigning false to a boolean attribute in the last line inside that callback method. Explicitly write return true in your callback methods to make this work (or just true at the end if your callback is a block (as noted by Jesse Wolgamott in the comments)).

UPDATE: This will no longer be an issue starting Rails 5.0, as return false will no longer halt the callback chain (throw :abort will now halt the callback chain).

UPDATE: You might also receive ActiveRecord::RecordNotSaved: Failed to save the record if a callback returns false.

Sign up to request clarification or add additional context in comments.

2 Comments

This worked great! One update: you must write "true" at the end of your before_validation block. "return true" will fail since it's in a block.
this also includes before_save I guess, since writing nil as the last line of my before save fixed this!
0

I think the problem lies in the controller code. The order variable is set before the line item is destroyed, and is not aware it's been destroyed afterwards. This code should really be in the model:

# line_item.rb
after_destroy :update_totals!
delegate :update_totals, :to=> :order

And the controller should just destroy the line item.

Comments

0

Regarding 1. Why is my activerecord errors model not saying what the validation error is?, see if you have the gem i18n installed. If you do, try uninstalling or an earlier version of the gem i18n.

gem uninstall i18n

Comments

0

It looks to me like you are using Ruby 1.8.7. Have you tried running your app using Ruby 1.9.3?

Comments

0

When you create other register in a before_validation method, if it fails, the error will be thrown by the 'father' class, so it won't show error, just <ActiveRecord::RecordInvalid: Validation failed: > I noticed that when I got an error in my 'child' record using byebug inside before validation method

Comments

0

Throwing a reply in here as it took a bit for us to track this down. We were upgrading to Rails 5.2 and suddenly started getting this exception.

It was due to us overriding destroyed? on the model (we were soft deleting items).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.