transactions.rb 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. #---
  2. # Excerpted from "Agile Web Development with Rails",
  3. # published by The Pragmatic Bookshelf.
  4. # Copyrights apply to this code. It may not be used to create training material,
  5. # courses, books, articles, and the like. Contact us if you are in doubt.
  6. # We make no guarantees that this code is fit for any purpose.
  7. # Visit http://www.pragmaticprogrammer.com/titles/rails4 for more book information.
  8. #---
  9. #---
  10. # Excerpted from "Agile Web Development with Rails, 4rd Ed.",
  11. # published by The Pragmatic Bookshelf.
  12. # Copyrights apply to this code. It may not be used to create training material,
  13. # courses, books, articles, and the like. Contact us if you are in doubt.
  14. # We make no guarantees that this code is fit for any purpose.
  15. # Visit http://www.pragmaticprogrammer.com/titles/rails4 for more book information.
  16. #---
  17. $: << File.dirname(__FILE__)
  18. require "connect"
  19. require "logger"
  20. #ActiveRecord::Base.logger = Logger.new(STDERR)
  21. require "rubygems"
  22. require "active_record"
  23. ActiveRecord::Schema.define do
  24. create_table :accounts, :force => true do |t|
  25. t.string :number
  26. t.decimal :balance, :precision => 10, :scale => 2, :default => 0
  27. end
  28. end
  29. class Account < ActiveRecord::Base
  30. validate :price_must_be_at_least_a_cent
  31. def self.transfer(from, to, amount)
  32. transaction(from, to) do
  33. from.withdraw(amount)
  34. to.deposit(amount)
  35. end
  36. end
  37. def withdraw(amount)
  38. adjust_balance_and_save(-amount)
  39. end
  40. def deposit(amount)
  41. adjust_balance_and_save(amount)
  42. end
  43. private
  44. def adjust_balance_and_save(amount)
  45. self.balance += amount
  46. save!
  47. end
  48. def price_must_be_at_least_a_cent
  49. errors.add(:balance, "is negative") if balance < 0
  50. end
  51. end
  52. def adjust_balance_and_save(amount)
  53. self.balance += amount
  54. end
  55. peter = Account.create(:balance => 100, :number => "12345")
  56. paul = Account.create(:balance => 200, :number => "54321")
  57. case ARGV[0] || "1"
  58. when "1"
  59. Account.transaction do
  60. paul.deposit(10)
  61. peter.withdraw(10)
  62. end
  63. when "2"
  64. Account.transaction do
  65. paul.deposit(350)
  66. peter.withdraw(350)
  67. end
  68. when "3"
  69. begin
  70. Account.transaction do
  71. paul.deposit(350)
  72. peter.withdraw(350)
  73. end
  74. rescue
  75. puts "Transfer aborted"
  76. end
  77. puts "Paul has #{paul.balance}"
  78. puts "Peter has #{peter.balance}"
  79. when "4"
  80. begin
  81. Account.transaction(peter, paul) do
  82. paul.deposit(350)
  83. peter.withdraw(350)
  84. end
  85. rescue
  86. puts "Transfer aborted"
  87. end
  88. puts "Paul has #{paul.balance}"
  89. puts "Peter has #{peter.balance}"
  90. when "5"
  91. Account.transfer(peter, paul, 350) rescue puts "Transfer aborted"
  92. puts "Paul has #{paul.balance}"
  93. puts "Peter has #{peter.balance}"
  94. end