【问题标题】:Rails update_column from within seeds.rb来自 seed.rb 的 Rails update_column
【发布时间】:2015-04-12 21:20:40
【问题描述】:

我有一个种子文件,可以生成大量对象,包括账户账户交易。创建账户后,一个循环会为每个账户生成 80 笔交易(有 150 个账户)。

一切正常,除了我需要更新帐户的 balance 列以反映交易引起的变化。我已经尝试了 100 种不同的方法。这是我最近的方法:

来自 seeds.rb

accounts.each do |account|
    80.times do
        type = types.sample
            case (type)
                when 1
                    description = descriptions_ATM_Withdrawal.sample
                    amount = (atm_amounts.sample) *-1
                when 2
                    description = descriptions_Check.sample
                    amount = ((500.0 - 5.0) * rand() + 5) *-1
                when 3
                    description = descriptions_Deposit.sample
                    amount = (2000.0 - 5.0) * rand() + 5
                when 4
                    description = descriptions_AutoDraft.sample
                    amount = ((350.0 - 5.0) * rand() + 5) *-1
                when 5
                    description = descriptions_POS.sample
                    amount = ((150.0 - 5.0) * rand() + 5) *-1
                when 6
                    description = descriptions_Transfer
                    amount = (500.0 - 5.0) * rand() + 5
                when 7
                    description = descriptions_Withdrawal
                    amount = ((500.0 - 5.0) * rand() + 5) *-1
                when 99
                    description = descriptions_Miscellaneous
                    amount = ((500.0 - 5.0) * rand() + 5) *-1
            end
        AcctTransaction.create do |transaction|
            transaction.id = SecureRandom.random_number(99999999999999)
            transaction.account_id = account.id
            transaction.transaction_type_id = type
            transaction.description = description
            transaction.amount = amount
            transaction.adjusted_bal = account.balance + transaction.amount
            # keep transaction in chronological order unless it's the first one
            unless AcctTransaction.exists?(account_id: transaction.account_id)
                transaction.date = rand(account.date_opened..Time.now)
            else
                transaction.date = rand(AcctTransaction.where(account_id: transaction.account_id).last.date..Time.now)
            end
        end
        Account.find(AcctTransaction.last.account_id).update_column(:balance, AcctTransaction.last.adjusted_bal)
    end
end

尝试使用“结束”之前的最后一行进行更新。我尝试了 update、update_attribute 以及“=”。似乎没有任何效果。帐户的“余额”字段必须在每次交易后更新,以便为帐户交易创建循环的下一次迭代中的计算提供准确的基础。

我们会考虑任何建议。这不可能那么难。同样,如果余额按应有的方式更新,整个事情就会正常工作。

Rails 4.1.8 / Ruby 2.1.5

请帮忙..谢谢!

编辑 account.rb:

class Account < ActiveRecord::Base
    belongs_to :customer
    belongs_to :user
    has_one :acct_type
    has_many :acct_transactions, :dependent => :destroy

    accepts_nested_attributes_for :acct_type
    accepts_nested_attributes_for :acct_transactions

    validates :acct_type_id, presence: true

end

acct_transaction.rb

class AcctTransaction < ActiveRecord::Base

    belongs_to :account
    has_one :transaction_type

    accepts_nested_attributes_for :transaction_type, :allow_destroy => false

end

(错误)结果的屏幕截图

如您所见,发生的是原始余额(放大后在标题中看到),持续存在。因此,每笔交易都是根据此金额计算的。

acct_transactions_controller 中实际用于在应用上线时执行这些更新的方法。在创建嵌套种子时尝试复制此功能:

  public
    def modify_acct_balance
      account = Account.find(@acct_transaction.account_id)
      case @acct_transaction.transaction_type_id
          when 1,2,4,5,7
              account.update(balance: account.balance - @acct_transaction.amount)
          when 3
            account.update(balance: account.balance + @acct_transaction.amount)
      end
    end

    def adjust_balance
      case @acct_transaction.transaction_type_id
          when 2,4,5,7
            @acct_transaction.adjusted_bal = Account.find(@acct_transaction.account_id).balance - @acct_transaction.amount
          when 3
            @acct_transaction.adjusted_bal = Account.find(@acct_transaction.account_id).balance + @acct_transaction.amount
      end
    end

请注意,上述方法根据交易类型(+ 或 -)计算不同 - 用户始终提供正值。虽然有效。

如何在上述种子文件中重现这种功能?

谢谢

【问题讨论】:

    标签: ruby-on-rails ruby activerecord seeding


    【解决方案1】:

    当然,有很多方法可以做到这一点,但乍一看,您的方法似乎可行。我的第一个想法是,您在与您的逻辑冲突的模型上有一些生命周期挂钩或计数器缓存配置。 (您可能想向我们展示您的模型定义)

    如果不是这样,我会在每次交易后跳过更新余额,并在交易创建循环结束时计算余额。

    在伪中:

    accounts.each do |account|
      80.times do
        # create transactions
      end
    
      account.reload
      account.balance = account.transactions.sum(:adjusted_bal)
      account.save
    end
    

    甚至更快,在交易创建期间在本地构建和缓存余额:

    accounts.each do |account|
      balance = 0
      80.times do
        # create transaction
        balance += transaction.amount
      end
      account.balance = balance
      account.save
    end
    

    【讨论】:

    • 谢谢,但是创建交易的循环需要根据它在上次迭代中所做的更改提供“最新”余额。我有兴趣看看是什么阻止了这一点。将 account.rbacct_transaction.rb 添加到上述帖子中。此外,我正在发布我在这些交易的结果视图中尝试实现的屏幕剪辑 - 以澄清。另外,我忘了说 acct_transactions_controller 具有完美更新两个模型中的余额字段的方法(通过用户操作触发)。但是,无法在种子中访问这些。
    【解决方案2】:

    要完成这项工作,我必须做两件事:

    1. 将更新方法(seeds.rb 的最后一行)的语法更改为:account.update(balance: transaction.adjusted_bal)
    2. 添加一个! (砰)创建方法(AcctTransaction.create! do |transaction|

    create 方法在没有爆炸声的情况下可能工作得很好,但我把它留在里面是因为现在一切都很好。另外,我不确定为什么使用 update 只适用于这种语法。我尝试了其他变体和其他方法来更新此专栏,但似乎都没有奏效。几乎看起来像seeds.rb 只适用于“基本”的Rails 方法。感谢 Deeno 和所有帮助我解决这个问题的人。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-12-20
      • 1970-01-01
      • 2012-10-14
      • 1970-01-01
      • 2017-02-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多