Rails - Проблемы с рефакторингом создания вложенных атрибутов контроллера - PullRequest
1 голос
/ 25 сентября 2011

У меня есть модели:

Transaction has_many :credits, :debits
Credit belongs_to :transaction
Debit belongs_to :transaction

Каждый кредит должен иметь балансирующий дебет, и наоборот.

В настоящее время я (успешно) достигаю этого с помощью следующего метода создания транзакции:

@transaction = Transaction.new(params[:transaction])

Transaction.transaction  do

  # Balance debits with credits (Sales)
  if params[:balance_transaction] == 'credit'
    @transaction.credits.each do |credit|
      @transaction.debits.push(Debit.new({
        :quantity => 0,
        :cost_per_unit => 0,
        :description => 'Balancing Debit',
        :amount => credit.amount,
        :account_id => 23 #Get from settings in future to allow users to choose Debtor account
      }))
    end
  elsif params[:balance_transaction] == 'debit'
    @transaction.debits.each do |debit|
      @transaction.credits.push(Credit.new({
        :quantity => 0,
        :cost_per_unit => 0,
        :description => 'Balancing Credit',
        :amount => credit.amount,
        :account_id => 43 #Get from settings in future to allow users to choose Creditor account
      }))
    end
  else
    raise ActiveRecord::Rollback # There's no balancing transaction. Don't save it!
  end

end

Я попытался переместить создание баланса дебет / кредит в модели дебет / кредит, заменив @transactions.credits.push(...) with debit.balancing_credit и добавив в модель дебета следующее:

def balancing_credit
  transaction.credits.new({
    :quantity => 0,
    :cost_per_unit => 0,
    :description => 'Balancing Debit',
    :amount => amount,
    :account_id => 43 #Get from settings in future to allow users to choose Creditor account
  })
end

Я думал, что это довольно простой рефакторинг, но он выдает ошибку undefined method 'debits' for nil:NilClass. Кажется, он ищет в базе данных еще не сохраненную транзакцию для создания балансирующего кредита? Я что-то не так делаю?

1 Ответ

1 голос
/ 25 сентября 2011

Вы правы в том, что такой механизм должен принадлежать моделям, а не контроллеру.У вас может быть обратный вызов before_save для вашей модели транзакции:

class Transaction
  after_save :balance_operations

  def balance_operations
    if credits
      credits.each do|credit|
        debit = debits.build (#do all your stuff here. build() automaticly fills the transaction_id field of your new debit with the proper id)
        return false unless debit.save
      end
    if debits # can use elsif if mutually exclusive conditions
      # same thing as above
    end
  end
 end

Это зависит от того факта, что цепочка обратных вызовов заключена в ActiveRecord :: Base.transaction.Если обратный вызов возвращает false, ActiveRecord выполнит откат.См. Главу «транзакция» здесь для получения дополнительной информации.

Если у вас много операций в одной транзакции, вы также можете взглянуть на улучшить производительность .

Редактировать: Вы также можете добавить validates_associated :debit, :credits к вашей модели

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...