ActiveRecord::Base#save! silently failing

Hello,

One of my AR models is failing to save (using rails 2.0.2 and sqlite3). Both #save and #save return (sometimes other values), but A) nothing ever hits the database, and B) #save! doesn't throw an error, even if it's not a valid model. See the irb session below, as well as my Order class and migration.

Has this happened to anyone else?

The most unusual thing I've done on this project so far is use the decimal column type in the Order model. I'm going to change it to float and see if that works, then try my hand at ruby-debug if it doesn't.

Many thanks, -Ed Brannin

t = Transaction.new

=> #<Transaction id: nil, order_id: nil, data: nil, txn_id: nil, handshake: nil, created_at: nil, updated_at: nil>

t.valid?

=> false

t.save

=> false

t.save!

ActiveRecord::RecordInvalid: Validation failed: Handshake can't be blank, Txn can't be blank, Data can't be blank   from /opt/local/lib/ruby/gems/1.8/gems/activerecord-2.0.2/lib/ active_record/validations.rb:946:in `save_without_transactions!'   from /opt/local/lib/ruby/gems/1.8/gems/activerecord-2.0.2/lib/ active_record/transactions.rb:112:in `save!'   from /opt/local/lib/ruby/gems/1.8/gems/activerecord-2.0.2/lib/ active_record/connection_adapters/abstract/database_statements.rb: 66:in `transaction'   from /opt/local/lib/ruby/gems/1.8/gems/activerecord-2.0.2/lib/ active_record/transactions.rb:80:in `transaction'   from /opt/local/lib/ruby/gems/1.8/gems/activerecord-2.0.2/lib/ active_record/transactions.rb:100:in `transaction'   from /opt/local/lib/ruby/gems/1.8/gems/activerecord-2.0.2/lib/ active_record/transactions.rb:112:in `save!'   from /opt/local/lib/ruby/gems/1.8/gems/activerecord-2.0.2/lib/ active_record/transactions.rb:120:in `rollback_active_record_state!'   from /opt/local/lib/ruby/gems/1.8/gems/activerecord-2.0.2/lib/ active_record/transactions.rb:112:in `save!'   from (irb):4

o = Order.new

=> #<Order id: nil, name: "", email: "", company: "", gross: nil, shipping: nil, handling: nil, address: "", status: "", created_at: nil, updated_at: nil>

o.valid?

=> false

o.save

=>

o.save!

=>

class Order < ActiveRecord::Base   validates_presence_of :name, :email, :address

validates_numericality_of :gross, :shipping, :handling, :greater_than_or_equal_to => 0

  has_many :transaction

  def total     gross + shipping + handling   end end

...and its migration: class CreateOrders < ActiveRecord::Migration   def self.up     create_table :orders do |t|       t.string :name, :default => "", :null => false       t.string :email, :default => "", :null => false       t.string :company, :default => "", :null => false       t.decimal :gross, :null => false       t.decimal :shipping, :null => false       t.decimal :handling, :null => false       t.text :address, :default => "", :null => false       t.string :status, :default => "", :null => false

      t.timestamps     end   end

  def self.down     drop_table :orders   end end

Relevant gem versions: action_profiler (1.0.0) actionmailer (2.0.2, 2.0.1, 1.3.6, 1.3.3, 1.3.2, 1.3.1, 1.2.5, 1.2.3, 1.2.2, 1.2.1) actionpack (2.0.2, 2.0.1, 1.13.6, 1.13.3, 1.13.2, 1.13.1, 1.12.5, 1.12.3, 1.12.2, 1.12.1) actionwebservice (1.2.6, 1.2.3, 1.2.2, 1.2.1, 1.1.6, 1.1.4, 1.1.3, 1.1.2) activerecord (2.0.2, 2.0.1, 1.15.6, 1.15.3, 1.15.2, 1.15.1, 1.14.4, 1.14.3, 1.14.2) activeresource (2.0.2, 2.0.1) activesupport (2.0.2, 2.0.1, 1.4.4, 1.4.2, 1.4.1, 1.4.0, 1.3.1) acts_as_versioned (0.2.3) json (1.1.2, 1.0.2, 0.4.3, 0.4.2) mongrel (1.1.3, 1.1.2, 1.0.1, 1.0, 0.3.14, 0.3.13.4, 0.3.13.3) mongrel_cluster (1.0.5, 0.2.1, 0.2.0) rails (2.0.2, 2.0.1, 1.2.6, 1.2.3, 1.2.2, 1.2.1, 1.1.6, 1.1.4, 1.1.3, 1.1.2) rails-app-installer (0.2.0, 0.1.5, 0.1.3) rails_analyzer_tools (1.4.0, 1.1.0) rspec (1.1.2, 1.1.1, 1.1.0, 1.0.5, 0.7.5.1, 0.7.5, 0.6.4, 0.6.3) rubygems-update (1.0.1, 0.9.5, 0.9.4) sqlite-ruby (2.2.3) sqlite3-ruby (1.2.1, 1.2.0, 1.1.0.1, 1.1.0) ZenTest (3.8.0, 3.7.2, 3.7.1, 3.6.1, 3.6.0)

Update:

Not surprisingly, the decimal vs float thing was a silly pipe-dream. I then tried defining ALL the ActiveRecord callbacks to puts their names and ran my specs. The 4 validation-related ones fire when I call #valid?, but *none* of them fired on #save.

I'm stepping through ActiveRecord's #save! in rdebug now, but I don't really expect to find my way through. Any help y'all can offer would be most appreciated.

Thank you, -Ed

Update:

Not surprisingly, the decimal vs float thing was a silly pipe-dream. I then tried defining ALL the ActiveRecord callbacks to puts their names and ran my specs. The 4 validation-related ones fire when I call #valid?, but *none* of them fired on #save.

I'm stepping through ActiveRecord's #save! in rdebug now, but I don't really expect to find my way through. Any help y'all can offer would be most appreciated.

I'll guess that Order has_one :transaction. This unfortunately is a
bad thing. AR::Base already has a transaction method, which executes the supplied
block in a transaction. Paraphrasing wildly, at the end of the day, some the save methods boil
down to

transaction do    #do some saving, invoke callbacks etc... end

But on your order model, transaction is just an association accessor
and so the saving never gets done.

Fred

I'll guess that Order has_one :transaction. This unfortunately is a bad thing. AR::Base already has a transaction method, which executes the supplied block in a transaction.

ack! I feel quite silly for not thinking of that.

Actually, it has_many :transaction, so when I changed it

Thank you!

-Ed