21 Action Controller: Routing and URLs 19 ActiveRecord: Relationships Between Tables
irb e1/ar/encrypt.rb
>> $: << File.dirname(__FILE__)
=> ["/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/will_paginate-3.0.3/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/test-unit-2.5.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/sqlite3-1.3.6/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/mysql-2.8.1/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/mysql-2.8.1/ext", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/minitest-3.2.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/jquery-rails-0.2.7/lib", "/home/rubys/git/rails/lib", "/home/rubys/git/rails/railties/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/thor-0.14.6/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/rdoc-3.12/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/json-1.7.3/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/htmlentities-4.3.1/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/haml-3.1.6/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/capistrano-2.12.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/net-ssh-gateway-1.1.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/net-sftp-2.0.5/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/net-scp-1.0.4/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/net-ssh-2.5.2/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/highline-1.6.13/lib", "/home/rubys/git/rails/activeresource/lib", "/home/rubys/git/rails/activerecord/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/arel-2.0.10/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/activemerchant-1.10.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/braintree-2.16.0/lib", "/home/rubys/git/rails/actionmailer/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/mail-2.2.19/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/treetop-1.4.10/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/polyglot-0.3.3/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/mime-types-1.19/lib", "/home/rubys/git/rails/actionpack/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/tzinfo-0.3.33/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/rack-test-0.5.7/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/rack-mount-0.6.14/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/rack-1.2.5/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/erubis-2.6.6/lib", "/home/rubys/git/rails/activemodel/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/i18n-0.5.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/builder-2.1.2/lib", "/home/rubys/git/rails/activesupport/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/abstract-1.0.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/rake-0.9.2.2/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/bundler-1.1.3/lib", "/home/rubys/git/gorp/lib", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/site_ruby/1.8", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/site_ruby/1.8/x86_64-linux", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/site_ruby", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/vendor_ruby/1.8", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/vendor_ruby/1.8/x86_64-linux", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/vendor_ruby", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/1.8", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/1.8/x86_64-linux", ".", "/home/rubys/git/awdwr/edition3/data/code/e1/ar"]
>> require "connect"
=> true
>> require "rubygems"
=> false
>> require "active_record"
=> false
>> ActiveRecord::Schema.define do
?> create_table :orders, :force => true do |t|
?> t.integer :user_id
>> t.string :name
>> t.string :address
>> t.string :email
>> end
>> create_table :users, :force => :true do |t|
?> t.string :name
>> end
>> end
-- create_table(:orders, {:force=>true})
-> 0.2901s
-- create_table(:users, {:force=>:true})
-> 0.2153s
=> nil
?> class ActiveRecord::Base
>> def self.encrypt(*attr_names)
>> encrypter = Encrypter.new(attr_names)
>> before_save encrypter
>> after_save encrypter
>> after_find encrypter
>> define_method(:after_find) { }
>> end
>> end
=> nil
?> class Encrypter
>> # We're passed a list of attributes that should
?> # be stored encrypted in the database
?> def initialize(attrs_to_manage)
>> @attrs_to_manage = attrs_to_manage
>> end
>> # Before saving or updating, encrypt the fields using the NSA and
?> # DHS approved Shift Cipher
?> def before_save(model)
>> @attrs_to_manage.each do |field|
?> model[field].tr!("a-z", "b-za")
>> end
>> end
>> # After saving, decrypt them back
?> def after_save(model)
>> @attrs_to_manage.each do |field|
?> model[field].tr!("b-za", "a-z")
>> end
>> end
>> # Do the same after finding an existing record
?> alias_method :after_find, :after_save
>> end
=> Encrypter
?> class Order < ActiveRecord::Base
>> encrypt(:name, :email)
>> end
=> #<Proc:0x0000000000000000@/home/rubys/git/awdwr/edition3/data/code/e1/ar/encrypt.rb:33>
?> o = Order.new
=> #<Order id: nil, user_id: nil, name: nil, address: nil, email: nil>
>> o.name = "Dave Thomas"
=> "Dave Thomas"
>> o.address = "123 The Street"
=> "123 The Street"
>> o.email = "dave@example.com"
=> "dave@example.com"
>> o.save
=> true
>> puts o.name
Dave Thomas
=> nil
>> o = Order.find(o.id)
=> #<Order id: 1, user_id: nil, name: "Dave Thomas", address: "123 The Street", email: "dave@example.com">
>> puts o.name
Dave Thomas
=> nil
>> >> => nil
sqlite3> select * from orders
id = 1
user_id =
name = Dbwf Tipnbt
address = 123 The Street
email = ebwf@fybnqmf.dpn
irb e1/ar/observer.rb
>> $: << File.dirname(__FILE__)
=> ["/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/will_paginate-3.0.3/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/test-unit-2.5.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/sqlite3-1.3.6/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/mysql-2.8.1/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/mysql-2.8.1/ext", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/minitest-3.2.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/jquery-rails-0.2.7/lib", "/home/rubys/git/rails/lib", "/home/rubys/git/rails/railties/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/thor-0.14.6/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/rdoc-3.12/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/json-1.7.3/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/htmlentities-4.3.1/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/haml-3.1.6/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/capistrano-2.12.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/net-ssh-gateway-1.1.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/net-sftp-2.0.5/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/net-scp-1.0.4/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/net-ssh-2.5.2/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/highline-1.6.13/lib", "/home/rubys/git/rails/activeresource/lib", "/home/rubys/git/rails/activerecord/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/arel-2.0.10/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/activemerchant-1.10.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/braintree-2.16.0/lib", "/home/rubys/git/rails/actionmailer/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/mail-2.2.19/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/treetop-1.4.10/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/polyglot-0.3.3/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/mime-types-1.19/lib", "/home/rubys/git/rails/actionpack/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/tzinfo-0.3.33/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/rack-test-0.5.7/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/rack-mount-0.6.14/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/rack-1.2.5/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/erubis-2.6.6/lib", "/home/rubys/git/rails/activemodel/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/i18n-0.5.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/builder-2.1.2/lib", "/home/rubys/git/rails/activesupport/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/abstract-1.0.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/rake-0.9.2.2/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/bundler-1.1.3/lib", "/home/rubys/git/gorp/lib", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/site_ruby/1.8", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/site_ruby/1.8/x86_64-linux", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/site_ruby", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/vendor_ruby/1.8", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/vendor_ruby/1.8/x86_64-linux", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/vendor_ruby", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/1.8", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/1.8/x86_64-linux", ".", "/home/rubys/git/awdwr/edition3/data/code/e1/ar"]
>> require "rubygems"
=> false
>> require "active_record"
=> true
>> require 'connect'
=> true
>> ActiveRecord::Base.logger = Logger.new(STDERR)
=> #<Logger:0x7f4d09c33f40 @formatter=nil, @level=0, @progname=nil, @default_formatter=#<Logger::Formatter:0x7f4d09c33ef0 @datetime_format=nil>, @logdev=#<Logger::LogDevice:0x7f4d09c33ea0 @shift_size=nil, @filename=nil, @shift_age=nil, @dev=#<IO:0x7f4d0feb1aa0>, @mutex=#<Logger::LogDevice::LogDeviceMutex:0x7f4d09c33e50 @mon_entering_queue=[], @mon_count=0, @mon_owner=nil, @mon_waiting_queue=[]>>>
>> ActiveRecord::Schema.define do
?> create_table :payments, :force => true do |t|
?> end
>> end
-- create_table(:payments, {:force=>true})
*[1m*[36mSQL (0.2ms) *[1mselect sqlite_version(*)
*[1m*[35mSQL (1.0ms) SELECT name
FROM sqlite_master
WHERE type = 'table' AND NOT name = 'sqlite_sequence'
-> 0.1844s
=> nil
>> class Order < ActiveRecord::Base
>> end
=> nil
>> class Payment < ActiveRecord::Base
>> end
=> nil
>> class Refund < ActiveRecord::Base
>> end
=> nil
?> class OrderObserver < ActiveRecord::Observer
*[1m*[36mSQL (165.6ms) *[1mCREATE TABLE "payments" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)
>> def after_save(an_order)
>> an_order.logger.info("Order #{an_order.id} created")
>> end
>> end
=> nil
>> OrderObserver.instance
=> #<OrderObserver:0x7f4d09ae78f8>
?> class AuditObserver < ActiveRecord::Observer
>> observe Order, Payment, Refund
>> def after_save(model)
>> model.logger.info("[Audit] #{model.class.name} #{model.id} created")
>> end
>> end
=> nil
>> AuditObserver.instance
=> #<AuditObserver:0x7f4d09ab67d0>
>> o = Order.create
*[1m*[35mSQL (0.5ms) SELECT name
FROM sqlite_master
WHERE type = 'table' AND NOT name = 'sqlite_sequence'
*[1m*[36mAREL (0.3ms) *[1mINSERT INTO "orders" ("email", "name", "address", "user_id") VALUES (NULL, NULL, NULL, NULL)
Order 2 created
[Audit] Order 2 created
=> #<Order id: 2, user_id: nil, name: nil, address: nil, email: nil>
>> p = Payment.create
*[1m*[35mAREL (0.3ms) INSERT INTO "payments" VALUES(NULL)
[Audit] Payment 1 created
=> #<Payment id: 1>
?> >>
irb e1/ar/attributes.rb
>> $: << File.dirname(__FILE__)
=> ["/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/will_paginate-3.0.3/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/test-unit-2.5.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/sqlite3-1.3.6/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/mysql-2.8.1/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/mysql-2.8.1/ext", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/minitest-3.2.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/jquery-rails-0.2.7/lib", "/home/rubys/git/rails/lib", "/home/rubys/git/rails/railties/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/thor-0.14.6/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/rdoc-3.12/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/json-1.7.3/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/htmlentities-4.3.1/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/haml-3.1.6/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/capistrano-2.12.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/net-ssh-gateway-1.1.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/net-sftp-2.0.5/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/net-scp-1.0.4/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/net-ssh-2.5.2/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/highline-1.6.13/lib", "/home/rubys/git/rails/activeresource/lib", "/home/rubys/git/rails/activerecord/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/arel-2.0.10/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/activemerchant-1.10.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/braintree-2.16.0/lib", "/home/rubys/git/rails/actionmailer/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/mail-2.2.19/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/treetop-1.4.10/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/polyglot-0.3.3/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/mime-types-1.19/lib", "/home/rubys/git/rails/actionpack/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/tzinfo-0.3.33/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/rack-test-0.5.7/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/rack-mount-0.6.14/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/rack-1.2.5/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/erubis-2.6.6/lib", "/home/rubys/git/rails/activemodel/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/i18n-0.5.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/builder-2.1.2/lib", "/home/rubys/git/rails/activesupport/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/abstract-1.0.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/rake-0.9.2.2/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/bundler-1.1.3/lib", "/home/rubys/git/gorp/lib", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/site_ruby/1.8", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/site_ruby/1.8/x86_64-linux", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/site_ruby", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/vendor_ruby/1.8", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/vendor_ruby/1.8/x86_64-linux", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/vendor_ruby", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/1.8", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/1.8/x86_64-linux", ".", "/home/rubys/git/awdwr/edition3/data/code/e1/ar"]
>> require "connect"
=> true
>> require "logger"
=> false
>> require "pp"
=> true
>> #ActiveRecord::Base.logger = Logger.new(STDERR)
?> require "rubygems"
=> false
>> require "active_record"
=> false
>> class LineItem < ActiveRecord::Base
>> end
=> nil
>> LineItem.delete_all
=> 1
>> LineItem.create(:quantity => 1, :product_id => 27, :order_id => 13, :unit_price => 29.95)
=> #<LineItem id: 3, product_id: 27, order_id: 13, quantity: 1, unit_price: #<BigDecimal:7f67b609d790,'0.2995E2',18(18)>>
>> LineItem.create(:quantity => 2, :unit_price => 29.95)
=> #<LineItem id: 4, product_id: nil, order_id: nil, quantity: 2, unit_price: #<BigDecimal:7f67b60807d0,'0.2995E2',18(18)>>
>> LineItem.create(:quantity => 1, :unit_price => 44.95)
=> #<LineItem id: 5, product_id: nil, order_id: nil, quantity: 1, unit_price: #<BigDecimal:7f67b606efd0,'0.4495E2',18(18)>>
>> result = LineItem.find(:first)
=> #<LineItem id: 3, product_id: 27, order_id: 13, quantity: 1, unit_price: #<BigDecimal:7f67b60638b0,'0.2995E2',18(18)>>
>> p result.quantity
1
=> nil
>> p result.unit_price
#<BigDecimal:7f67b6058898,'0.2995E2',18(18)>
=> nil
>> result = LineItem.find_by_sql("select quantity, quantity*unit_price " +
?> "from line_items")
=> [#<LineItem quantity: 1>, #<LineItem quantity: 2>, #<LineItem quantity: 1>]
>> pp result[0].attributes
{"quantity*unit_price"=>29.95, "quantity"=>1}
=> nil
>> result = LineItem.find_by_sql("select quantity,
quantity*unit_price as total_price " +
?> "from line_items")
=> [#<LineItem quantity: 1>, #<LineItem quantity: 2>, #<LineItem quantity: 1>]
>> pp result[0].attributes
{"quantity"=>1, "total_price"=>29.95}
=> nil
>> p result[0].total_price
29.95
=> nil
>> sales_tax = 0.07
=> 0.07
>> p result[0].total_price * sales_tax
2.0965
=> nil
>> class LineItem < ActiveRecord::Base
>> def total_price
>> Float(read_attribute("total_price"))
>> end
>> CUBITS_TO_INCHES = 2.54
>> def quantity
>> read_attribute("quantity") * CUBITS_TO_INCHES
>> end
>> def quantity=(inches)
>> write_attribute("quantity", Float(inches) / CUBITS_TO_INCHES)
>> end
>> end
=> nil
>> p result[0].quantity
2.54
=> nil
>> result[0].quantity = 500
=> 500
>> p result[0].save
true
=> nil
?> >>
sqlite3> select id, quantity*unit_price from line_items
id = 3
quantity*unit_price = 29.95
id = 4
quantity*unit_price = 59.9
id = 5
quantity*unit_price = 44.95
irb e1/ar/transactions.rb 1
>> $: << File.dirname(__FILE__)
=> ["/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/will_paginate-3.0.3/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/test-unit-2.5.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/sqlite3-1.3.6/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/mysql-2.8.1/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/mysql-2.8.1/ext", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/minitest-3.2.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/jquery-rails-0.2.7/lib", "/home/rubys/git/rails/lib", "/home/rubys/git/rails/railties/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/thor-0.14.6/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/rdoc-3.12/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/json-1.7.3/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/htmlentities-4.3.1/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/haml-3.1.6/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/capistrano-2.12.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/net-ssh-gateway-1.1.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/net-sftp-2.0.5/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/net-scp-1.0.4/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/net-ssh-2.5.2/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/highline-1.6.13/lib", "/home/rubys/git/rails/activeresource/lib", "/home/rubys/git/rails/activerecord/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/arel-2.0.10/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/activemerchant-1.10.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/braintree-2.16.0/lib", "/home/rubys/git/rails/actionmailer/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/mail-2.2.19/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/treetop-1.4.10/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/polyglot-0.3.3/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/mime-types-1.19/lib", "/home/rubys/git/rails/actionpack/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/tzinfo-0.3.33/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/rack-test-0.5.7/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/rack-mount-0.6.14/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/rack-1.2.5/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/erubis-2.6.6/lib", "/home/rubys/git/rails/activemodel/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/i18n-0.5.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/builder-2.1.2/lib", "/home/rubys/git/rails/activesupport/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/abstract-1.0.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/rake-0.9.2.2/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/bundler-1.1.3/lib", "/home/rubys/git/gorp/lib", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/site_ruby/1.8", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/site_ruby/1.8/x86_64-linux", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/site_ruby", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/vendor_ruby/1.8", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/vendor_ruby/1.8/x86_64-linux", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/vendor_ruby", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/1.8", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/1.8/x86_64-linux", ".", "/home/rubys/git/awdwr/edition3/data/code/e1/ar"]
>> require "connect"
=> true
>> require "logger"
=> false
>> #ActiveRecord::Base.logger = Logger.new(STDERR)
?> require "rubygems"
=> false
>> require "active_record"
=> false
>> ActiveRecord::Schema.define do
?> create_table :accounts, :force => true do |t|
?> t.string :number
>> t.decimal :balance, :precision => 10, :scale => 2, :default => 0
>> end
>> end
-- create_table(:accounts, {:force=>true})
-> 0.1814s
=> nil
?> class Account < ActiveRecord::Base
>> validate :price_must_be_at_least_a_cent
>> def self.transfer(from, to, amount)
>> transaction(from, to) do
?> from.withdraw(amount)
>> to.deposit(amount)
>> end
>> end
?> def withdraw(amount)
>> adjust_balance_and_save(-amount)
>> end
>> def deposit(amount)
>> adjust_balance_and_save(amount)
>> end
>> private
>> def adjust_balance_and_save(amount)
>> self.balance += amount
>> save!
>> end
>> def price_must_be_at_least_a_cent
>> errors.add(:balance, "is negative") if balance < 0
>> end
>> end
=> nil
?> def adjust_balance_and_save(amount)
>> self.balance += amount
>> end
=> nil
?> peter = Account.create(:balance => 100, :number => "12345")
=> #<Account id: 1, number: "12345", balance: #<BigDecimal:7ffe389b52b0,'0.1E3',9(18)>>
>> paul = Account.create(:balance => 200, :number => "54321")
=> #<Account id: 2, number: "54321", balance: #<BigDecimal:7ffe389a1ff8,'0.2E3',9(18)>>
>> case ARGV[0] || "1"
>> when "1"
>> Account.transaction do
?> paul.deposit(10)
>> peter.withdraw(10)
>> end
>> when "2"
>> Account.transaction do
?> paul.deposit(350)
>> peter.withdraw(350)
>> end
>> when "3"
>> begin
?> Account.transaction do
?> paul.deposit(350)
>> peter.withdraw(350)
>> end
>> rescue
>> puts "Transfer aborted"
>> end
>> puts "Paul has #{paul.balance}"
>> puts "Peter has #{peter.balance}"
>> when "4"
>> begin
?> Account.transaction(peter, paul) do
?> paul.deposit(350)
>> peter.withdraw(350)
>> end
>> rescue
>> puts "Transfer aborted"
>> end
>> puts "Paul has #{paul.balance}"
>> puts "Peter has #{peter.balance}"
>> when "5"
>> Account.transfer(peter, paul, 350) rescue puts "Transfer aborted"
>> puts "Paul has #{paul.balance}"
>> puts "Peter has #{peter.balance}"
>> end
=> true
>> >> => nil
sqlite3> select * from accounts
id = 1
number = 12345
balance = 90
id = 2
number = 54321
balance = 210
irb e1/ar/transactions.rb 2
>> $: << File.dirname(__FILE__)
=> ["/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/will_paginate-3.0.3/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/test-unit-2.5.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/sqlite3-1.3.6/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/mysql-2.8.1/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/mysql-2.8.1/ext", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/minitest-3.2.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/jquery-rails-0.2.7/lib", "/home/rubys/git/rails/lib", "/home/rubys/git/rails/railties/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/thor-0.14.6/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/rdoc-3.12/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/json-1.7.3/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/htmlentities-4.3.1/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/haml-3.1.6/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/capistrano-2.12.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/net-ssh-gateway-1.1.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/net-sftp-2.0.5/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/net-scp-1.0.4/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/net-ssh-2.5.2/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/highline-1.6.13/lib", "/home/rubys/git/rails/activeresource/lib", "/home/rubys/git/rails/activerecord/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/arel-2.0.10/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/activemerchant-1.10.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/braintree-2.16.0/lib", "/home/rubys/git/rails/actionmailer/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/mail-2.2.19/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/treetop-1.4.10/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/polyglot-0.3.3/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/mime-types-1.19/lib", "/home/rubys/git/rails/actionpack/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/tzinfo-0.3.33/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/rack-test-0.5.7/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/rack-mount-0.6.14/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/rack-1.2.5/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/erubis-2.6.6/lib", "/home/rubys/git/rails/activemodel/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/i18n-0.5.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/builder-2.1.2/lib", "/home/rubys/git/rails/activesupport/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/abstract-1.0.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/rake-0.9.2.2/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/bundler-1.1.3/lib", "/home/rubys/git/gorp/lib", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/site_ruby/1.8", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/site_ruby/1.8/x86_64-linux", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/site_ruby", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/vendor_ruby/1.8", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/vendor_ruby/1.8/x86_64-linux", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/vendor_ruby", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/1.8", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/1.8/x86_64-linux", ".", "/home/rubys/git/awdwr/edition3/data/code/e1/ar"]
>> require "connect"
=> true
>> require "logger"
=> false
>> #ActiveRecord::Base.logger = Logger.new(STDERR)
?> require "rubygems"
=> false
>> require "active_record"
=> false
>> ActiveRecord::Schema.define do
?> create_table :accounts, :force => true do |t|
?> t.string :number
>> t.decimal :balance, :precision => 10, :scale => 2, :default => 0
>> end
>> end
-- create_table(:accounts, {:force=>true})
-> 0.2804s
=> nil
?> class Account < ActiveRecord::Base
>> validate :price_must_be_at_least_a_cent
>> def self.transfer(from, to, amount)
>> transaction(from, to) do
?> from.withdraw(amount)
>> to.deposit(amount)
>> end
>> end
?> def withdraw(amount)
>> adjust_balance_and_save(-amount)
>> end
>> def deposit(amount)
>> adjust_balance_and_save(amount)
>> end
>> private
>> def adjust_balance_and_save(amount)
>> self.balance += amount
>> save!
>> end
>> def price_must_be_at_least_a_cent
>> errors.add(:balance, "is negative") if balance < 0
>> end
>> end
=> nil
?> def adjust_balance_and_save(amount)
>> self.balance += amount
>> end
=> nil
?> peter = Account.create(:balance => 100, :number => "12345")
=> #<Account id: 1, number: "12345", balance: #<BigDecimal:7fc27d41eb40,'0.1E3',9(18)>>
>> paul = Account.create(:balance => 200, :number => "54321")
=> #<Account id: 2, number: "54321", balance: #<BigDecimal:7fc27d4096f0,'0.2E3',9(18)>>
>> case ARGV[0] || "1"
>> when "1"
>> Account.transaction do
?> paul.deposit(10)
>> peter.withdraw(10)
>> end
>> when "2"
>> Account.transaction do
?> paul.deposit(350)
>> peter.withdraw(350)
>> end
>> when "3"
>> begin
?> Account.transaction do
?> paul.deposit(350)
>> peter.withdraw(350)
>> end
>> rescue
>> puts "Transfer aborted"
>> end
>> puts "Paul has #{paul.balance}"
>> puts "Peter has #{peter.balance}"
>> when "4"
>> begin
?> Account.transaction(peter, paul) do
?> paul.deposit(350)
>> peter.withdraw(350)
>> end
>> rescue
>> puts "Transfer aborted"
>> end
>> puts "Paul has #{paul.balance}"
>> puts "Peter has #{peter.balance}"
>> when "5"
>> Account.transfer(peter, paul, 350) rescue puts "Transfer aborted"
>> puts "Paul has #{paul.balance}"
>> puts "Peter has #{peter.balance}"
>> end
ActiveRecord::RecordInvalid: Validation failed: Balance is negative
from /home/rubys/git/rails/activerecord/lib/active_record/validations.rb:49:in `save!'
from /home/rubys/git/rails/activerecord/lib/active_record/attribute_methods/dirty.rb:30:in `save!'
from /home/rubys/git/rails/activerecord/lib/active_record/transactions.rb:245:in `save!'
from /home/rubys/git/rails/activerecord/lib/active_record/transactions.rb:292:in `with_transaction_returning_status'
from /home/rubys/git/rails/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb:139:in `transaction'
from /home/rubys/git/rails/activerecord/lib/active_record/transactions.rb:207:in `transaction'
from /home/rubys/git/rails/activerecord/lib/active_record/transactions.rb:290:in `with_transaction_returning_status'
from /home/rubys/git/rails/activerecord/lib/active_record/transactions.rb:245:in `save!'
from /home/rubys/git/awdwr/edition3/data/code/e1/ar/transactions.rb:48:in `adjust_balance_and_save'
from /home/rubys/git/awdwr/edition3/data/code/e1/ar/transactions.rb:37:in `withdraw'
from /home/rubys/git/awdwr/edition3/data/code/e1/ar/transactions.rb:84
from /home/rubys/git/rails/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb:139:in `transaction'
from /home/rubys/git/rails/activerecord/lib/active_record/transactions.rb:207:in `transaction'
from /home/rubys/git/awdwr/edition3/data/code/e1/ar/transactions.rb:82
>> >> => nil
sqlite3> select * from accounts
id = 1
number = 12345
balance = 100
id = 2
number = 54321
balance = 200
irb e1/ar/transactions.rb 3
>> $: << File.dirname(__FILE__)
=> ["/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/will_paginate-3.0.3/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/test-unit-2.5.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/sqlite3-1.3.6/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/mysql-2.8.1/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/mysql-2.8.1/ext", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/minitest-3.2.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/jquery-rails-0.2.7/lib", "/home/rubys/git/rails/lib", "/home/rubys/git/rails/railties/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/thor-0.14.6/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/rdoc-3.12/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/json-1.7.3/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/htmlentities-4.3.1/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/haml-3.1.6/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/capistrano-2.12.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/net-ssh-gateway-1.1.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/net-sftp-2.0.5/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/net-scp-1.0.4/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/net-ssh-2.5.2/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/highline-1.6.13/lib", "/home/rubys/git/rails/activeresource/lib", "/home/rubys/git/rails/activerecord/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/arel-2.0.10/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/activemerchant-1.10.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/braintree-2.16.0/lib", "/home/rubys/git/rails/actionmailer/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/mail-2.2.19/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/treetop-1.4.10/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/polyglot-0.3.3/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/mime-types-1.19/lib", "/home/rubys/git/rails/actionpack/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/tzinfo-0.3.33/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/rack-test-0.5.7/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/rack-mount-0.6.14/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/rack-1.2.5/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/erubis-2.6.6/lib", "/home/rubys/git/rails/activemodel/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/i18n-0.5.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/builder-2.1.2/lib", "/home/rubys/git/rails/activesupport/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/abstract-1.0.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/rake-0.9.2.2/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/bundler-1.1.3/lib", "/home/rubys/git/gorp/lib", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/site_ruby/1.8", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/site_ruby/1.8/x86_64-linux", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/site_ruby", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/vendor_ruby/1.8", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/vendor_ruby/1.8/x86_64-linux", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/vendor_ruby", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/1.8", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/1.8/x86_64-linux", ".", "/home/rubys/git/awdwr/edition3/data/code/e1/ar"]
>> require "connect"
=> true
>> require "logger"
=> false
>> #ActiveRecord::Base.logger = Logger.new(STDERR)
?> require "rubygems"
=> false
>> require "active_record"
=> false
>> ActiveRecord::Schema.define do
?> create_table :accounts, :force => true do |t|
?> t.string :number
>> t.decimal :balance, :precision => 10, :scale => 2, :default => 0
>> end
>> end
-- create_table(:accounts, {:force=>true})
-> 0.3051s
=> nil
?> class Account < ActiveRecord::Base
>> validate :price_must_be_at_least_a_cent
>> def self.transfer(from, to, amount)
>> transaction(from, to) do
?> from.withdraw(amount)
>> to.deposit(amount)
>> end
>> end
?> def withdraw(amount)
>> adjust_balance_and_save(-amount)
>> end
>> def deposit(amount)
>> adjust_balance_and_save(amount)
>> end
>> private
>> def adjust_balance_and_save(amount)
>> self.balance += amount
>> save!
>> end
>> def price_must_be_at_least_a_cent
>> errors.add(:balance, "is negative") if balance < 0
>> end
>> end
=> nil
?> def adjust_balance_and_save(amount)
>> self.balance += amount
>> end
=> nil
?> peter = Account.create(:balance => 100, :number => "12345")
=> #<Account id: 1, number: "12345", balance: #<BigDecimal:7f6d11c010e0,'0.1E3',9(18)>>
>> paul = Account.create(:balance => 200, :number => "54321")
=> #<Account id: 2, number: "54321", balance: #<BigDecimal:7f6d11be9990,'0.2E3',9(18)>>
>> case ARGV[0] || "1"
>> when "1"
>> Account.transaction do
?> paul.deposit(10)
>> peter.withdraw(10)
>> end
>> when "2"
>> Account.transaction do
?> paul.deposit(350)
>> peter.withdraw(350)
>> end
>> when "3"
>> begin
?> Account.transaction do
?> paul.deposit(350)
>> peter.withdraw(350)
>> end
>> rescue
>> puts "Transfer aborted"
>> end
>> puts "Paul has #{paul.balance}"
>> puts "Peter has #{peter.balance}"
>> when "4"
>> begin
?> Account.transaction(peter, paul) do
?> paul.deposit(350)
>> peter.withdraw(350)
>> end
>> rescue
>> puts "Transfer aborted"
>> end
>> puts "Paul has #{paul.balance}"
>> puts "Peter has #{peter.balance}"
>> when "5"
>> Account.transfer(peter, paul, 350) rescue puts "Transfer aborted"
>> puts "Paul has #{paul.balance}"
>> puts "Peter has #{peter.balance}"
>> end
Transfer aborted
Paul has 550.0
Peter has -250.0
=> nil
>> >> => nil
irb e1/ar/transactions.rb 4
>> $: << File.dirname(__FILE__)
=> ["/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/will_paginate-3.0.3/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/test-unit-2.5.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/sqlite3-1.3.6/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/mysql-2.8.1/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/mysql-2.8.1/ext", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/minitest-3.2.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/jquery-rails-0.2.7/lib", "/home/rubys/git/rails/lib", "/home/rubys/git/rails/railties/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/thor-0.14.6/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/rdoc-3.12/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/json-1.7.3/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/htmlentities-4.3.1/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/haml-3.1.6/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/capistrano-2.12.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/net-ssh-gateway-1.1.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/net-sftp-2.0.5/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/net-scp-1.0.4/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/net-ssh-2.5.2/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/highline-1.6.13/lib", "/home/rubys/git/rails/activeresource/lib", "/home/rubys/git/rails/activerecord/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/arel-2.0.10/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/activemerchant-1.10.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/braintree-2.16.0/lib", "/home/rubys/git/rails/actionmailer/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/mail-2.2.19/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/treetop-1.4.10/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/polyglot-0.3.3/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/mime-types-1.19/lib", "/home/rubys/git/rails/actionpack/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/tzinfo-0.3.33/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/rack-test-0.5.7/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/rack-mount-0.6.14/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/rack-1.2.5/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/erubis-2.6.6/lib", "/home/rubys/git/rails/activemodel/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/i18n-0.5.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/builder-2.1.2/lib", "/home/rubys/git/rails/activesupport/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/abstract-1.0.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/rake-0.9.2.2/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/bundler-1.1.3/lib", "/home/rubys/git/gorp/lib", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/site_ruby/1.8", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/site_ruby/1.8/x86_64-linux", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/site_ruby", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/vendor_ruby/1.8", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/vendor_ruby/1.8/x86_64-linux", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/vendor_ruby", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/1.8", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/1.8/x86_64-linux", ".", "/home/rubys/git/awdwr/edition3/data/code/e1/ar"]
>> require "connect"
=> true
>> require "logger"
=> false
>> #ActiveRecord::Base.logger = Logger.new(STDERR)
?> require "rubygems"
=> false
>> require "active_record"
=> false
>> ActiveRecord::Schema.define do
?> create_table :accounts, :force => true do |t|
?> t.string :number
>> t.decimal :balance, :precision => 10, :scale => 2, :default => 0
>> end
>> end
-- create_table(:accounts, {:force=>true})
-> 0.3309s
=> nil
?> class Account < ActiveRecord::Base
>> validate :price_must_be_at_least_a_cent
>> def self.transfer(from, to, amount)
>> transaction(from, to) do
?> from.withdraw(amount)
>> to.deposit(amount)
>> end
>> end
?> def withdraw(amount)
>> adjust_balance_and_save(-amount)
>> end
>> def deposit(amount)
>> adjust_balance_and_save(amount)
>> end
>> private
>> def adjust_balance_and_save(amount)
>> self.balance += amount
>> save!
>> end
>> def price_must_be_at_least_a_cent
>> errors.add(:balance, "is negative") if balance < 0
>> end
>> end
=> nil
?> def adjust_balance_and_save(amount)
>> self.balance += amount
>> end
=> nil
?> peter = Account.create(:balance => 100, :number => "12345")
=> #<Account id: 1, number: "12345", balance: #<BigDecimal:7fdb63a12e30,'0.1E3',9(18)>>
>> paul = Account.create(:balance => 200, :number => "54321")
=> #<Account id: 2, number: "54321", balance: #<BigDecimal:7fdb639fb6e0,'0.2E3',9(18)>>
>> case ARGV[0] || "1"
>> when "1"
>> Account.transaction do
?> paul.deposit(10)
>> peter.withdraw(10)
>> end
>> when "2"
>> Account.transaction do
?> paul.deposit(350)
>> peter.withdraw(350)
>> end
>> when "3"
>> begin
?> Account.transaction do
?> paul.deposit(350)
>> peter.withdraw(350)
>> end
>> rescue
>> puts "Transfer aborted"
>> end
>> puts "Paul has #{paul.balance}"
>> puts "Peter has #{peter.balance}"
>> when "4"
>> begin
?> Account.transaction(peter, paul) do
?> paul.deposit(350)
>> peter.withdraw(350)
>> end
>> rescue
>> puts "Transfer aborted"
>> end
>> puts "Paul has #{paul.balance}"
>> puts "Peter has #{peter.balance}"
>> when "5"
>> Account.transfer(peter, paul, 350) rescue puts "Transfer aborted"
>> puts "Paul has #{paul.balance}"
>> puts "Peter has #{peter.balance}"
>> end
Transfer aborted
Paul has 200.0
Peter has 100.0
=> nil
>> >> => nil
irb e1/ar/transactions.rb 5
>> $: << File.dirname(__FILE__)
=> ["/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/will_paginate-3.0.3/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/test-unit-2.5.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/sqlite3-1.3.6/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/mysql-2.8.1/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/mysql-2.8.1/ext", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/minitest-3.2.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/jquery-rails-0.2.7/lib", "/home/rubys/git/rails/lib", "/home/rubys/git/rails/railties/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/thor-0.14.6/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/rdoc-3.12/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/json-1.7.3/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/htmlentities-4.3.1/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/haml-3.1.6/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/capistrano-2.12.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/net-ssh-gateway-1.1.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/net-sftp-2.0.5/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/net-scp-1.0.4/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/net-ssh-2.5.2/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/highline-1.6.13/lib", "/home/rubys/git/rails/activeresource/lib", "/home/rubys/git/rails/activerecord/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/arel-2.0.10/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/activemerchant-1.10.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/braintree-2.16.0/lib", "/home/rubys/git/rails/actionmailer/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/mail-2.2.19/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/treetop-1.4.10/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/polyglot-0.3.3/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/mime-types-1.19/lib", "/home/rubys/git/rails/actionpack/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/tzinfo-0.3.33/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/rack-test-0.5.7/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/rack-mount-0.6.14/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/rack-1.2.5/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/erubis-2.6.6/lib", "/home/rubys/git/rails/activemodel/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/i18n-0.5.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/builder-2.1.2/lib", "/home/rubys/git/rails/activesupport/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/abstract-1.0.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/rake-0.9.2.2/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/bundler-1.1.3/lib", "/home/rubys/git/gorp/lib", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/site_ruby/1.8", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/site_ruby/1.8/x86_64-linux", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/site_ruby", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/vendor_ruby/1.8", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/vendor_ruby/1.8/x86_64-linux", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/vendor_ruby", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/1.8", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/1.8/x86_64-linux", ".", "/home/rubys/git/awdwr/edition3/data/code/e1/ar"]
>> require "connect"
=> true
>> require "logger"
=> false
>> #ActiveRecord::Base.logger = Logger.new(STDERR)
?> require "rubygems"
=> false
>> require "active_record"
=> false
>> ActiveRecord::Schema.define do
?> create_table :accounts, :force => true do |t|
?> t.string :number
>> t.decimal :balance, :precision => 10, :scale => 2, :default => 0
>> end
>> end
-- create_table(:accounts, {:force=>true})
-> 0.3194s
=> nil
?> class Account < ActiveRecord::Base
>> validate :price_must_be_at_least_a_cent
>> def self.transfer(from, to, amount)
>> transaction(from, to) do
?> from.withdraw(amount)
>> to.deposit(amount)
>> end
>> end
?> def withdraw(amount)
>> adjust_balance_and_save(-amount)
>> end
>> def deposit(amount)
>> adjust_balance_and_save(amount)
>> end
>> private
>> def adjust_balance_and_save(amount)
>> self.balance += amount
>> save!
>> end
>> def price_must_be_at_least_a_cent
>> errors.add(:balance, "is negative") if balance < 0
>> end
>> end
=> nil
?> def adjust_balance_and_save(amount)
>> self.balance += amount
>> end
=> nil
?> peter = Account.create(:balance => 100, :number => "12345")
=> #<Account id: 1, number: "12345", balance: #<BigDecimal:7efef6066e30,'0.1E3',9(18)>>
>> paul = Account.create(:balance => 200, :number => "54321")
=> #<Account id: 2, number: "54321", balance: #<BigDecimal:7efef604f6e0,'0.2E3',9(18)>>
>> case ARGV[0] || "1"
>> when "1"
>> Account.transaction do
?> paul.deposit(10)
>> peter.withdraw(10)
>> end
>> when "2"
>> Account.transaction do
?> paul.deposit(350)
>> peter.withdraw(350)
>> end
>> when "3"
>> begin
?> Account.transaction do
?> paul.deposit(350)
>> peter.withdraw(350)
>> end
>> rescue
>> puts "Transfer aborted"
>> end
>> puts "Paul has #{paul.balance}"
>> puts "Peter has #{peter.balance}"
>> when "4"
>> begin
?> Account.transaction(peter, paul) do
?> paul.deposit(350)
>> peter.withdraw(350)
>> end
>> rescue
>> puts "Transfer aborted"
>> end
>> puts "Paul has #{paul.balance}"
>> puts "Peter has #{peter.balance}"
>> when "5"
>> Account.transfer(peter, paul, 350) rescue puts "Transfer aborted"
>> puts "Paul has #{paul.balance}"
>> puts "Peter has #{peter.balance}"
>> end
Transfer aborted
Paul has 200.0
Peter has 100.0
=> nil
>> >> => nil
irb e1/ar/optimistic.rb
>> $: << File.dirname(__FILE__)
=> ["/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/will_paginate-3.0.3/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/test-unit-2.5.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/sqlite3-1.3.6/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/mysql-2.8.1/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/mysql-2.8.1/ext", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/minitest-3.2.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/jquery-rails-0.2.7/lib", "/home/rubys/git/rails/lib", "/home/rubys/git/rails/railties/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/thor-0.14.6/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/rdoc-3.12/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/json-1.7.3/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/htmlentities-4.3.1/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/haml-3.1.6/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/capistrano-2.12.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/net-ssh-gateway-1.1.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/net-sftp-2.0.5/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/net-scp-1.0.4/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/net-ssh-2.5.2/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/highline-1.6.13/lib", "/home/rubys/git/rails/activeresource/lib", "/home/rubys/git/rails/activerecord/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/arel-2.0.10/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/activemerchant-1.10.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/braintree-2.16.0/lib", "/home/rubys/git/rails/actionmailer/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/mail-2.2.19/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/treetop-1.4.10/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/polyglot-0.3.3/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/mime-types-1.19/lib", "/home/rubys/git/rails/actionpack/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/tzinfo-0.3.33/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/rack-test-0.5.7/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/rack-mount-0.6.14/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/rack-1.2.5/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/erubis-2.6.6/lib", "/home/rubys/git/rails/activemodel/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/i18n-0.5.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/builder-2.1.2/lib", "/home/rubys/git/rails/activesupport/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/abstract-1.0.0/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/rake-0.9.2.2/lib", "/home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/bundler-1.1.3/lib", "/home/rubys/git/gorp/lib", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/site_ruby/1.8", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/site_ruby/1.8/x86_64-linux", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/site_ruby", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/vendor_ruby/1.8", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/vendor_ruby/1.8/x86_64-linux", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/vendor_ruby", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/1.8", "/home/rubys/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/1.8/x86_64-linux", ".", "/home/rubys/git/awdwr/edition3/data/code/e1/ar"]
>> require "connect"
=> true
>> require "rubygems"
=> false
>> require "active_record"
=> false
>> ActiveRecord::Schema.define do
?> create_table :counters, :force => true do |t|
?> t.integer :count
>> t.integer :lock_version, :default => 0
>> end
>> end
-- create_table(:counters, {:force=>true})
-> 0.2445s
=> nil
?> class Counter < ActiveRecord::Base
>> end
=> nil
>> Counter.delete_all
=> 0
>> Counter.create(:count => 0)
=> #<Counter id: 1, count: 0, lock_version: 0>
>> count1 = Counter.find(:first)
=> #<Counter id: 1, count: 0, lock_version: 0>
>> count2 = Counter.find(:first)
=> #<Counter id: 1, count: 0, lock_version: 0>
>> count1.count += 3
=> 3
>> count1.save
=> true
>> count2.count += 4
=> 4
>> count2.save
ActiveRecord::StaleObjectError: Attempted to update a stale object: Counter
from /home/rubys/git/rails/activerecord/lib/active_record/locking/optimistic.rb:97:in `update'
from /home/rubys/git/rails/activerecord/lib/active_record/attribute_methods/dirty.rb:68:in `update'
from /home/rubys/git/rails/activerecord/lib/active_record/timestamp.rb:60:in `update'
from /home/rubys/git/rails/activerecord/lib/active_record/callbacks.rb:281:in `update'
from /home/rubys/git/rails/activesupport/lib/active_support/callbacks.rb:414:in `_run_update_callbacks'
from /home/rubys/git/rails/activerecord/lib/active_record/callbacks.rb:281:in `update'
from /home/rubys/git/rails/activerecord/lib/active_record/persistence.rb:257:in `create_or_update'
from /home/rubys/git/rails/activerecord/lib/active_record/callbacks.rb:273:in `create_or_update'
from /home/rubys/git/rails/activesupport/lib/active_support/callbacks.rb:414:in `_run_save_callbacks'
from /home/rubys/git/rails/activerecord/lib/active_record/callbacks.rb:273:in `create_or_update'
from /home/rubys/git/rails/activerecord/lib/active_record/persistence.rb:40:in `save'
from /home/rubys/git/rails/activerecord/lib/active_record/validations.rb:43:in `save'
from /home/rubys/git/rails/activerecord/lib/active_record/attribute_methods/dirty.rb:21:in `save'
from /home/rubys/git/rails/activerecord/lib/active_record/transactions.rb:240:in `save'
from /home/rubys/git/rails/activerecord/lib/active_record/transactions.rb:292:in `with_transaction_returning_status'
from /home/rubys/git/rails/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb:139:in `transaction'
from /home/rubys/git/rails/activerecord/lib/active_record/transactions.rb:207:in `transaction'
from /home/rubys/git/rails/activerecord/lib/active_record/transactions.rb:290:in `with_transaction_returning_status'
from /home/rubys/git/rails/activerecord/lib/active_record/transactions.rb:240:in `save'
from /home/rubys/git/rails/activerecord/lib/active_record/transactions.rb:251:in `rollback_active_record_state!'
from /home/rubys/git/rails/activerecord/lib/active_record/transactions.rb:239:in `save'
from /home/rubys/git/awdwr/edition3/data/code/e1/ar/optimistic.rb:31>> #END:optimistic
?> >> => nil
21 Action Controller: Routing and URLs 19 ActiveRecord: Relationships Between Tables