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:insave!’
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:intransaction’
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:insave!’
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:insave!’
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

On 20 Jan 2008, at 02:48, Ed Brannin wrote:

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

On Jan 20, 7:57 am, Frederick C. [email protected]
wrote:

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
to :transactions, it started working just fine.

Thank you!

-Ed