21 Action Controller: Routing and URLs 19 ActiveRecord: Relationships Between Tables
irb e1/ar/encrypt.rb
/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/bundler-1.0.0.rc.3/lib/bundler.rb:183: Use RbConfig instead of obsolete and deprecated Config.
Switch to inspect mode.
>> $: << File.dirname(__FILE__)
=> ["/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/sqlite3-ruby-1.3.1/lib", "/home/rubys/git/rails/lib", "/home/rubys/git/rails/railties/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/thor-0.14.0/lib", "/home/rubys/git/rails/activeresource/lib", "/home/rubys/git/rails/activerecord/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/arel-0.4.0/lib", "/home/rubys/git/rails/actionmailer/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/mail-2.2.5/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/treetop-1.4.8/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/polyglot-0.3.1/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/mime-types-1.16/lib", "/home/rubys/git/rails/actionpack/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/tzinfo-0.3.22/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/rack-test-0.5.4/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/rack-mount-0.6.9/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/rack-1.2.1/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/erubis-2.6.6/lib", "/home/rubys/git/rails/activemodel/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/i18n-0.4.1/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/builder-2.1.2/lib", "/home/rubys/git/rails/activesupport/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/abstract-1.0.0/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/rake-0.8.7/lib", "/home/rubys/git/gorp/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/bundler-1.0.0.rc.3/lib", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/site_ruby/1.9.1", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/site_ruby/1.9.1/i686-linux", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/site_ruby", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/vendor_ruby/1.9.1", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/vendor_ruby/1.9.1/i686-linux", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/vendor_ruby", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/1.9.1", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/1.9.1/i686-linux", "/home/rubys/git/awdwr/data/code/e1/ar"]
>> require "connect"
=> true
>> require "rubygems"
=> nil
>> require "active_record"
=> nil
>> 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.0256s
-- create_table(:users, {:force=>:true})
-> 0.0072s
=> 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:0x92bd924@/home/rubys/git/awdwr/data/code/e1/ar/encrypt.rb:33 (lambda)>
?> 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
/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/bundler-1.0.0.rc.3/lib/bundler.rb:183: Use RbConfig instead of obsolete and deprecated Config.
Switch to inspect mode.
>> $: << File.dirname(__FILE__)
=> ["/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/sqlite3-ruby-1.3.1/lib", "/home/rubys/git/rails/lib", "/home/rubys/git/rails/railties/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/thor-0.14.0/lib", "/home/rubys/git/rails/activeresource/lib", "/home/rubys/git/rails/activerecord/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/arel-0.4.0/lib", "/home/rubys/git/rails/actionmailer/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/mail-2.2.5/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/treetop-1.4.8/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/polyglot-0.3.1/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/mime-types-1.16/lib", "/home/rubys/git/rails/actionpack/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/tzinfo-0.3.22/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/rack-test-0.5.4/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/rack-mount-0.6.9/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/rack-1.2.1/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/erubis-2.6.6/lib", "/home/rubys/git/rails/activemodel/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/i18n-0.4.1/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/builder-2.1.2/lib", "/home/rubys/git/rails/activesupport/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/abstract-1.0.0/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/rake-0.8.7/lib", "/home/rubys/git/gorp/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/bundler-1.0.0.rc.3/lib", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/site_ruby/1.9.1", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/site_ruby/1.9.1/i686-linux", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/site_ruby", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/vendor_ruby/1.9.1", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/vendor_ruby/1.9.1/i686-linux", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/vendor_ruby", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/1.9.1", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/1.9.1/i686-linux", "/home/rubys/git/awdwr/data/code/e1/ar"]
>> require "rubygems"
=> false
>> require "active_record"
=> true
>> require 'connect'
=> true
>> ActiveRecord::Base.logger = Logger.new(STDERR)
=> #<Logger:0x91a6c5c @progname=nil, @level=0, @default_formatter=#<Logger::Formatter:0x91a6c48 @datetime_format=nil>, @formatter=nil, @logdev=#<Logger::LogDevice:0x91a6c20 @shift_size=nil, @shift_age=nil, @filename=nil, @dev=#<IO:<STDERR>>, @mutex=#<Logger::LogDevice::LogDeviceMutex:0x91a6c0c @mon_owner=nil, @mon_count=0, @mon_mutex=#<Mutex:0x91a6be4>>>>
>> ActiveRecord::Schema.define do
?> create_table :payments, :force => true do |t|
?> end
>> end
-- create_table(:payments, {:force=>true})
*[1m*[36mSQL (1.0ms) *[1mselect sqlite_version(*)
*[1m*[35mSQL (0.4ms) SELECT name
FROM sqlite_master
WHERE type = 'table' AND NOT name = 'sqlite_sequence'
*[1m*[36mSQL (5.7ms) *[1mCREATE TABLE "payments" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)
-> 0.0241s
=> nil
>> class Order < ActiveRecord::Base
>> end
=> nil
>> class Payment < ActiveRecord::Base
>> end
=> nil
>> class Refund < ActiveRecord::Base
>> end
=> nil
?> class OrderObserver < ActiveRecord::Observer
>> def after_save(an_order)
>> an_order.logger.info("Order #{an_order.id} created")
>> end
>> end
=> nil
>> OrderObserver.instance
=> #<OrderObserver:0x92a35ec>
?> 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:0x92cde28>
>> o = Order.create
*[1m*[35mSQL (0.5ms) SELECT name
FROM sqlite_master
WHERE type = 'table' AND NOT name = 'sqlite_sequence'
*[1m*[36mSQL (0.4ms) *[1mINSERT INTO "orders" ("address", "email", "name", "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*[35mSQL (0.3ms) INSERT INTO "payments" VALUES(NULL)
[Audit] Payment 1 created
=> #<Payment id: 1>
irb e1/ar/attributes.rb
/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/bundler-1.0.0.rc.3/lib/bundler.rb:183: Use RbConfig instead of obsolete and deprecated Config.
Switch to inspect mode.
>> $: << File.dirname(__FILE__)
=> ["/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/sqlite3-ruby-1.3.1/lib", "/home/rubys/git/rails/lib", "/home/rubys/git/rails/railties/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/thor-0.14.0/lib", "/home/rubys/git/rails/activeresource/lib", "/home/rubys/git/rails/activerecord/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/arel-0.4.0/lib", "/home/rubys/git/rails/actionmailer/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/mail-2.2.5/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/treetop-1.4.8/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/polyglot-0.3.1/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/mime-types-1.16/lib", "/home/rubys/git/rails/actionpack/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/tzinfo-0.3.22/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/rack-test-0.5.4/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/rack-mount-0.6.9/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/rack-1.2.1/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/erubis-2.6.6/lib", "/home/rubys/git/rails/activemodel/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/i18n-0.4.1/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/builder-2.1.2/lib", "/home/rubys/git/rails/activesupport/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/abstract-1.0.0/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/rake-0.8.7/lib", "/home/rubys/git/gorp/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/bundler-1.0.0.rc.3/lib", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/site_ruby/1.9.1", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/site_ruby/1.9.1/i686-linux", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/site_ruby", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/vendor_ruby/1.9.1", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/vendor_ruby/1.9.1/i686-linux", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/vendor_ruby", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/1.9.1", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/1.9.1/i686-linux", "/home/rubys/git/awdwr/data/code/e1/ar"]
>> require "connect"
=> true
>> require "logger"
=> nil
>> require "pp"
=> ["PP"]
>> #ActiveRecord::Base.logger = Logger.new(STDERR)
?> require "rubygems"
=> nil
>> require "active_record"
=> nil
>> 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:865a330,'0.2995E2',8(8)>>
>> LineItem.create(:quantity => 2, :unit_price => 29.95)
=> #<LineItem id: 4, product_id: nil, order_id: nil, quantity: 2, unit_price: #<BigDecimal:86cf158,'0.2995E2',8(8)>>
>> LineItem.create(:quantity => 1, :unit_price => 44.95)
=> #<LineItem id: 5, product_id: nil, order_id: nil, quantity: 1, unit_price: #<BigDecimal:89faff8,'0.4495E2',8(8)>>
>> result = LineItem.find(:first)
=> #<LineItem id: 3, product_id: 27, order_id: 13, quantity: 1, unit_price: #<BigDecimal:8a16d34,'0.2995E2',8(8)>>
>> p result.quantity
1
=> 1
>> p result.unit_price
#<BigDecimal:8a26b1c,'0.2995E2',8(8)>
=> #<BigDecimal:8a26b1c,'0.2995E2',8(8)>
>> 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"=>1, "quantity*unit_price"=>29.95}
=> {"quantity"=>1, "quantity*unit_price"=>29.95}
>> 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}
=> {"quantity"=>1, "total_price"=>29.95}
>> p result[0].total_price
29.95
=> 29.95
>> sales_tax = 0.07
=> 0.07
>> p result[0].total_price * sales_tax
2.0965000000000003
=> 2.0965000000000003
>> 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
=> 2.54
>> result[0].quantity = 500
=> 500
>> p result[0].save
true
=> true
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
/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/bundler-1.0.0.rc.3/lib/bundler.rb:183: Use RbConfig instead of obsolete and deprecated Config.
Switch to inspect mode.
>> $: << File.dirname(__FILE__)
=> ["/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/sqlite3-ruby-1.3.1/lib", "/home/rubys/git/rails/lib", "/home/rubys/git/rails/railties/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/thor-0.14.0/lib", "/home/rubys/git/rails/activeresource/lib", "/home/rubys/git/rails/activerecord/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/arel-0.4.0/lib", "/home/rubys/git/rails/actionmailer/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/mail-2.2.5/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/treetop-1.4.8/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/polyglot-0.3.1/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/mime-types-1.16/lib", "/home/rubys/git/rails/actionpack/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/tzinfo-0.3.22/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/rack-test-0.5.4/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/rack-mount-0.6.9/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/rack-1.2.1/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/erubis-2.6.6/lib", "/home/rubys/git/rails/activemodel/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/i18n-0.4.1/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/builder-2.1.2/lib", "/home/rubys/git/rails/activesupport/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/abstract-1.0.0/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/rake-0.8.7/lib", "/home/rubys/git/gorp/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/bundler-1.0.0.rc.3/lib", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/site_ruby/1.9.1", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/site_ruby/1.9.1/i686-linux", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/site_ruby", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/vendor_ruby/1.9.1", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/vendor_ruby/1.9.1/i686-linux", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/vendor_ruby", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/1.9.1", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/1.9.1/i686-linux", "/home/rubys/git/awdwr/data/code/e1/ar"]
>> require "connect"
=> true
>> require "logger"
=> nil
>> #ActiveRecord::Base.logger = Logger.new(STDERR)
?> require "rubygems"
=> nil
>> require "active_record"
=> nil
>> 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.0331s
=> 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:8241f64,'0.1E3',4(8)>>
>> paul = Account.create(:balance => 200, :number => "54321")
=> #<Account id: 2, number: "54321", balance: #<BigDecimal:84622e4,'0.2E3',4(8)>>
>> 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
/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/bundler-1.0.0.rc.3/lib/bundler.rb:183: Use RbConfig instead of obsolete and deprecated Config.
Switch to inspect mode.
>> $: << File.dirname(__FILE__)
=> ["/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/sqlite3-ruby-1.3.1/lib", "/home/rubys/git/rails/lib", "/home/rubys/git/rails/railties/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/thor-0.14.0/lib", "/home/rubys/git/rails/activeresource/lib", "/home/rubys/git/rails/activerecord/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/arel-0.4.0/lib", "/home/rubys/git/rails/actionmailer/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/mail-2.2.5/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/treetop-1.4.8/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/polyglot-0.3.1/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/mime-types-1.16/lib", "/home/rubys/git/rails/actionpack/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/tzinfo-0.3.22/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/rack-test-0.5.4/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/rack-mount-0.6.9/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/rack-1.2.1/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/erubis-2.6.6/lib", "/home/rubys/git/rails/activemodel/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/i18n-0.4.1/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/builder-2.1.2/lib", "/home/rubys/git/rails/activesupport/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/abstract-1.0.0/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/rake-0.8.7/lib", "/home/rubys/git/gorp/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/bundler-1.0.0.rc.3/lib", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/site_ruby/1.9.1", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/site_ruby/1.9.1/i686-linux", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/site_ruby", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/vendor_ruby/1.9.1", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/vendor_ruby/1.9.1/i686-linux", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/vendor_ruby", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/1.9.1", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/1.9.1/i686-linux", "/home/rubys/git/awdwr/data/code/e1/ar"]
>> require "connect"
=> true
>> require "logger"
=> nil
>> #ActiveRecord::Base.logger = Logger.new(STDERR)
?> require "rubygems"
=> nil
>> require "active_record"
=> nil
>> 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.0340s
=> 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:82474a0,'0.1E3',4(8)>>
>> paul = Account.create(:balance => 200, :number => "54321")
=> #<Account id: 2, number: "54321", balance: #<BigDecimal:8473918,'0.2E3',4(8)>>
>> 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:242:in `block in save!'
from /home/rubys/git/rails/activerecord/lib/active_record/transactions.rb:289:in `block 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:204:in `transaction'
from /home/rubys/git/rails/activerecord/lib/active_record/transactions.rb:287:in `with_transaction_returning_status'
from /home/rubys/git/rails/activerecord/lib/active_record/transactions.rb:242:in `save!'
from /home/rubys/git/awdwr/data/code/e1/ar/transactions.rb:48:in `adjust_balance_and_save'
from /home/rubys/git/awdwr/data/code/e1/ar/transactions.rb:37:in `withdraw'
from /home/rubys/git/awdwr/data/code/e1/ar/transactions.rb:84:in `block in irb_binding'
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:204:in `transaction'
from /home/rubys/git/awdwr/data/code/e1/ar/transactions.rb:82
from /home/rubys/.rvm/rubies/ruby-1.9.3-r28929/bin/irb:17:in `<main>'
=> nil
sqlite3> select * from accounts
id = 1
number = 12345
balance = 100
id = 2
number = 54321
balance = 200
irb e1/ar/transactions.rb 3
/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/bundler-1.0.0.rc.3/lib/bundler.rb:183: Use RbConfig instead of obsolete and deprecated Config.
Switch to inspect mode.
>> $: << File.dirname(__FILE__)
=> ["/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/sqlite3-ruby-1.3.1/lib", "/home/rubys/git/rails/lib", "/home/rubys/git/rails/railties/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/thor-0.14.0/lib", "/home/rubys/git/rails/activeresource/lib", "/home/rubys/git/rails/activerecord/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/arel-0.4.0/lib", "/home/rubys/git/rails/actionmailer/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/mail-2.2.5/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/treetop-1.4.8/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/polyglot-0.3.1/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/mime-types-1.16/lib", "/home/rubys/git/rails/actionpack/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/tzinfo-0.3.22/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/rack-test-0.5.4/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/rack-mount-0.6.9/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/rack-1.2.1/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/erubis-2.6.6/lib", "/home/rubys/git/rails/activemodel/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/i18n-0.4.1/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/builder-2.1.2/lib", "/home/rubys/git/rails/activesupport/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/abstract-1.0.0/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/rake-0.8.7/lib", "/home/rubys/git/gorp/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/bundler-1.0.0.rc.3/lib", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/site_ruby/1.9.1", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/site_ruby/1.9.1/i686-linux", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/site_ruby", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/vendor_ruby/1.9.1", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/vendor_ruby/1.9.1/i686-linux", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/vendor_ruby", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/1.9.1", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/1.9.1/i686-linux", "/home/rubys/git/awdwr/data/code/e1/ar"]
>> require "connect"
=> true
>> require "logger"
=> nil
>> #ActiveRecord::Base.logger = Logger.new(STDERR)
?> require "rubygems"
=> nil
>> require "active_record"
=> nil
>> 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.0354s
=> 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:8242090,'0.1E3',4(8)>>
>> paul = Account.create(:balance => 200, :number => "54321")
=> #<Account id: 2, number: "54321", balance: #<BigDecimal:84756a0,'0.2E3',4(8)>>
>> 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
/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/bundler-1.0.0.rc.3/lib/bundler.rb:183: Use RbConfig instead of obsolete and deprecated Config.
Switch to inspect mode.
>> $: << File.dirname(__FILE__)
=> ["/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/sqlite3-ruby-1.3.1/lib", "/home/rubys/git/rails/lib", "/home/rubys/git/rails/railties/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/thor-0.14.0/lib", "/home/rubys/git/rails/activeresource/lib", "/home/rubys/git/rails/activerecord/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/arel-0.4.0/lib", "/home/rubys/git/rails/actionmailer/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/mail-2.2.5/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/treetop-1.4.8/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/polyglot-0.3.1/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/mime-types-1.16/lib", "/home/rubys/git/rails/actionpack/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/tzinfo-0.3.22/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/rack-test-0.5.4/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/rack-mount-0.6.9/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/rack-1.2.1/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/erubis-2.6.6/lib", "/home/rubys/git/rails/activemodel/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/i18n-0.4.1/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/builder-2.1.2/lib", "/home/rubys/git/rails/activesupport/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/abstract-1.0.0/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/rake-0.8.7/lib", "/home/rubys/git/gorp/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/bundler-1.0.0.rc.3/lib", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/site_ruby/1.9.1", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/site_ruby/1.9.1/i686-linux", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/site_ruby", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/vendor_ruby/1.9.1", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/vendor_ruby/1.9.1/i686-linux", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/vendor_ruby", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/1.9.1", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/1.9.1/i686-linux", "/home/rubys/git/awdwr/data/code/e1/ar"]
>> require "connect"
=> true
>> require "logger"
=> nil
>> #ActiveRecord::Base.logger = Logger.new(STDERR)
?> require "rubygems"
=> nil
>> require "active_record"
=> nil
>> 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.0376s
=> 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:8241d84,'0.1E3',4(8)>>
>> paul = Account.create(:balance => 200, :number => "54321")
=> #<Account id: 2, number: "54321", balance: #<BigDecimal:8460318,'0.2E3',4(8)>>
>> 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
/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/bundler-1.0.0.rc.3/lib/bundler.rb:183: Use RbConfig instead of obsolete and deprecated Config.
Switch to inspect mode.
>> $: << File.dirname(__FILE__)
=> ["/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/sqlite3-ruby-1.3.1/lib", "/home/rubys/git/rails/lib", "/home/rubys/git/rails/railties/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/thor-0.14.0/lib", "/home/rubys/git/rails/activeresource/lib", "/home/rubys/git/rails/activerecord/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/arel-0.4.0/lib", "/home/rubys/git/rails/actionmailer/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/mail-2.2.5/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/treetop-1.4.8/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/polyglot-0.3.1/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/mime-types-1.16/lib", "/home/rubys/git/rails/actionpack/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/tzinfo-0.3.22/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/rack-test-0.5.4/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/rack-mount-0.6.9/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/rack-1.2.1/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/erubis-2.6.6/lib", "/home/rubys/git/rails/activemodel/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/i18n-0.4.1/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/builder-2.1.2/lib", "/home/rubys/git/rails/activesupport/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/abstract-1.0.0/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/rake-0.8.7/lib", "/home/rubys/git/gorp/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/bundler-1.0.0.rc.3/lib", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/site_ruby/1.9.1", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/site_ruby/1.9.1/i686-linux", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/site_ruby", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/vendor_ruby/1.9.1", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/vendor_ruby/1.9.1/i686-linux", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/vendor_ruby", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/1.9.1", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/1.9.1/i686-linux", "/home/rubys/git/awdwr/data/code/e1/ar"]
>> require "connect"
=> true
>> require "logger"
=> nil
>> #ActiveRecord::Base.logger = Logger.new(STDERR)
?> require "rubygems"
=> nil
>> require "active_record"
=> nil
>> 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.0365s
=> 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:8241e4c,'0.1E3',4(8)>>
>> paul = Account.create(:balance => 200, :number => "54321")
=> #<Account id: 2, number: "54321", balance: #<BigDecimal:8460610,'0.2E3',4(8)>>
>> 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
/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/bundler-1.0.0.rc.3/lib/bundler.rb:183: Use RbConfig instead of obsolete and deprecated Config.
Switch to inspect mode.
>> $: << File.dirname(__FILE__)
=> ["/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/sqlite3-ruby-1.3.1/lib", "/home/rubys/git/rails/lib", "/home/rubys/git/rails/railties/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/thor-0.14.0/lib", "/home/rubys/git/rails/activeresource/lib", "/home/rubys/git/rails/activerecord/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/arel-0.4.0/lib", "/home/rubys/git/rails/actionmailer/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/mail-2.2.5/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/treetop-1.4.8/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/polyglot-0.3.1/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/mime-types-1.16/lib", "/home/rubys/git/rails/actionpack/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/tzinfo-0.3.22/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/rack-test-0.5.4/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/rack-mount-0.6.9/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/rack-1.2.1/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/erubis-2.6.6/lib", "/home/rubys/git/rails/activemodel/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/i18n-0.4.1/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/builder-2.1.2/lib", "/home/rubys/git/rails/activesupport/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/abstract-1.0.0/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/rake-0.8.7/lib", "/home/rubys/git/gorp/lib", "/home/rubys/.rvm/gems/ruby-1.9.3-r28929/gems/bundler-1.0.0.rc.3/lib", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/site_ruby/1.9.1", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/site_ruby/1.9.1/i686-linux", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/site_ruby", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/vendor_ruby/1.9.1", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/vendor_ruby/1.9.1/i686-linux", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/vendor_ruby", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/1.9.1", "/home/rubys/.rvm/rubies/ruby-1.9.3-r28929/lib/ruby/1.9.1/i686-linux", "/home/rubys/git/awdwr/data/code/e1/ar"]
>> require "connect"
=> true
>> require "rubygems"
=> nil
>> require "active_record"
=> nil
>> 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.0329s
=> 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:56:in `update'
from /home/rubys/git/rails/activerecord/lib/active_record/callbacks.rb:285:in `block in update'
from /home/rubys/git/rails/activesupport/lib/active_support/callbacks.rb:408:in `_run_update_callbacks'
from /home/rubys/git/rails/activerecord/lib/active_record/callbacks.rb:285:in `update'
from /home/rubys/git/rails/activerecord/lib/active_record/persistence.rb:237:in `create_or_update'
from /home/rubys/git/rails/activerecord/lib/active_record/callbacks.rb:277:in `block in create_or_update'
from /home/rubys/git/rails/activesupport/lib/active_support/callbacks.rb:408:in `_run_save_callbacks'
from /home/rubys/git/rails/activerecord/lib/active_record/callbacks.rb:277:in `create_or_update'
from /home/rubys/git/rails/activerecord/lib/active_record/persistence.rb:39: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:237:in `block (2 levels) in save'
from /home/rubys/git/rails/activerecord/lib/active_record/transactions.rb:289:in `block 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:204:in `transaction'
from /home/rubys/git/rails/activerecord/lib/active_record/transactions.rb:287:in `with_transaction_returning_status'
from /home/rubys/git/rails/activerecord/lib/active_record/transactions.rb:237:in `block in save'
from /home/rubys/git/rails/activerecord/lib/active_record/transactions.rb:248:in `rollback_active_record_state!'
from /home/rubys/git/rails/activerecord/lib/active_record/transactions.rb:236:in `save'
from /home/rubys/git/awdwr/data/code/e1/ar/optimistic.rb:31
from /home/rubys/.rvm/rubies/ruby-1.9.3-r28929/bin/irb:17:in `<main>'>> #END:optimistic
=> nil
21 Action Controller: Routing and URLs 19 ActiveRecord: Relationships Between Tables