Ruby on Rails新手求助:如何实现账户存款与取款功能?
解决方案
1. 先修正模型中的笔误
你的AccountTransaction模型存在两处语法/拼写错误,先修复:
validats拼写错误,正确写法为validatesSecureRandom.uu:id是语法错误,正确生成UUID的方法是SecureRandom.uuid
修正后的AccountTransaction模型:
class AccountTransaction < ApplicationRecord TRANSACTION_TYPES = ["withdraw", "deposit"] belongs_to :bank_account validates :bank_account, presence: true validates :amount, presence: true, numericality: true validates :transaction_number, presence: true, uniqueness: true validates :transaction_type, presence: true, inclusion: { in: TRANSACTION_TYPES } before_validation :load_defaults def load_defaults self.transaction_number = SecureRandom.uuid if new_record? end end
2. 给BankAccount添加存款/取款核心方法
在BankAccount模型中实现业务逻辑,用事务保证余额更新和交易记录的原子性(避免出现余额变了但没生成记录、或反之的数据不一致问题):
class BankAccount < ApplicationRecord belongs_to :client has_many :account_transactions, dependent: :destroy # 关联账户的交易记录 validates :account_number, presence: true, uniqueness: true validates :balance, presence: true, numericality: true before_validation :load_defaults def load_defaults self.balance = 0.00 if new_record? end def to_s account_number end # 存款方法 def deposit(amount) raise ArgumentError, "存款金额必须大于0" if amount <= 0 ActiveRecord::Base.transaction do self.balance += amount save! account_transactions.create!( amount: amount, transaction_type: "deposit" ) end true rescue ActiveRecord::RecordInvalid, ArgumentError => e errors.add(:base, e.message) false end # 取款方法 def withdraw(amount) raise ArgumentError, "取款金额必须大于0" if amount <= 0 raise ArgumentError, "余额不足,无法完成取款" if balance < amount ActiveRecord::Base.transaction do self.balance -= amount save! account_transactions.create!( amount: amount, transaction_type: "withdraw" ) end true rescue ActiveRecord::RecordInvalid, ArgumentError => e errors.add(:base, e.message) false end end
3. 配置嵌套路由
在config/routes.rb中添加嵌套路由,把存款/取款动作绑定到银行账户资源上:
Rails.application.routes.draw do resources :bank_accounts do member do post :deposit post :withdraw end end # 保留你原有的其他路由 end
运行rails routes可查看生成的路由:
POST /bank_accounts/:id/deposit→ 对应bank_accounts#deposit动作POST /bank_accounts/:id/withdraw→ 对应bank_accounts#withdraw动作
4. 完善控制器处理逻辑
在BankAccountsController中添加deposit和withdraw动作,处理表单提交的参数并调用模型方法:
class BankAccountsController < ApplicationController def index @bank_accounts = BankAccount.all end def show @bank_account = BankAccount.find(params[:id]) end def deposit @bank_account = BankAccount.find(params[:id]) amount = params[:amount].to_f if @bank_account.deposit(amount) flash[:notice] = "存款成功!当前余额:#{sprintf("%.2f", @bank_account.balance)}" redirect_to @bank_account else flash[:alert] = @bank_account.errors.full_messages.join(", ") render :show end end def withdraw @bank_account = BankAccount.find(params[:id]) amount = params[:amount].to_f if @bank_account.withdraw(amount) flash[:notice] = "取款成功!当前余额:#{sprintf("%.2f", @bank_account.balance)}" redirect_to @bank_account else flash[:alert] = @bank_account.errors.full_messages.join(", ") render :show end end end
5. 在视图中添加交易表单
修改app/views/bank_accounts/show.html.erb,添加存款和取款的提交表单:
<h1>账户:<%= @bank_account.account_number %></h1> <p>当前余额:<%= sprintf("%.2f", @bank_account.balance) %></p> <!-- 存款表单 --> <div class="transaction-form"> <h3>存款操作</h3> <%= form_with(url: deposit_bank_account_path(@bank_account), method: :post) do |form| %> <div> <%= form.label :amount, "存款金额" %> <%= form.number_field :amount, step: 0.01, min: 0.01, required: true %> </div> <%= form.submit "确认存款" %> <% end %> </div> <!-- 取款表单 --> <div class="transaction-form"> <h3>取款操作</h3> <%= form_with(url: withdraw_bank_account_path(@bank_account), method: :post) do |form| %> <div> <%= form.label :amount, "取款金额" %> <%= form.number_field :amount, step: 0.01, min: 0.01, required: true %> </div> <%= form.submit "确认取款" %> <% end %> </div> <!-- 显示交易记录(可选) --> <div class="transaction-history"> <h3>交易记录</h3> <ul> <% @bank_account.account_transactions.order(created_at: :desc).each do |tx| %> <li> <%= tx.transaction_type.capitalize %>: <%= sprintf("%.2f", tx.amount) %> <small><%= tx.created_at.strftime("%Y-%m-%d %H:%M") %></small> </li> <% end %> </ul> </div> <!-- 提示信息 --> <% if flash[:notice] %> <p style="color: green;"><%= flash[:notice] %></p> <% end %> <% if flash[:alert] %> <p style="color: red;"><%= flash[:alert] %></p> <% end %>
内容的提问来源于stack exchange,提问作者frank mbonu
相关产品推荐
相关产品推荐

