1

create - метод, который должен возвращать true только тогда, когда все прошло как ожидалось, а false - в противном случае. Я иду за потоком управления стилями ошибок.Возвращает внутренние транзакции и ActiveRecord :: Rollback

class TransferOperator 
    class TransferError < Struct.new(:type, :message); ; end 

    attr_reader :transfer, :error 

    def initialize(transfer) 
    @transfer = transfer 
    end 

    # Creates the transfer and locks money in the bank 
    def create 
    return error(:validation_error) if transfer.invalid? 

    to_bank = transfer.main_to_bank 
    to_bank.with_lock do 
     # How does return here behave? Should a raise be issued instead and caught outside? 
     return error(:insufficient_buffer) if to_bank.available_balance < transfer.amount 
     to_bank.available_balance -= transfer.amount 
     to_bank.locked_balance += transfer.amount 
     to_bank.save! 
     transfer.save! 
    end 

    # Is it guaranteed here that the above transaction has always been succesful? 
    true 
    end 

    private 

    def error(type, message='') 
    @error = TransferError.new(type, message) 
    false 
    end 
end 

Идея заключается в том, чтобы иметь такой поток для вызывающего абонента:

def move_money 
    @transfer = Transfer.new(params) 
    operator = TransferOperator.new(@transfer) 
    if operator.create 
    redirect_to :root, notice: 'success!' 
    else 
    if operator.error.type == :validation_error 
     render action: 'new' 
    elsif operator.error.type == :insufficient_buffer 
     redirect_to :root, notice: 'not enough money' 
    else 
     # Handle other errors here... 
    end 
    end 
end 

Что происходит с возвратом ошибки внутри транзакции?

Это гарантия того, что транзакция прошла успешно, если возвращается истина?

От http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html

Одним из исключений является ActiveRecord :: Откат исключение, которое будет вызвать ROLLBACK при подъеме, но не может быть повторно поднятый блок на сделки.

Возможно ли, что Rails поднимет ActiveRecord::Rollback сам по себе? Если это произойдет, транзакция будет терпеть неудачу и вернётся истина (это не то, что мы хотим).

ответ

2

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

  1. Raise ActiveRecord::Rollback и транзакция будет откат и ошибка не будет вновь поднят за пределами блока транзакции. Как вы сказали, это будет отменять транзакцию. Наверное, не то, что ты хочешь.
  2. Поднимите любой другой тип ошибки. Это приведет к откату транзакции, и ваша ошибка будет повышена. Вы можете спасти эту ошибку, чтобы перенаправить пользователя соответствующим образом.

Возврат объекта с ошибкой ничего не делает. Это еще один объект, который передается.

+0

Можно ли рассчитывать на Rails, не поднимая 'ActiveRecord :: Rollback' самостоятельно _inside_ транзакции? – randomguy

+1

Rails никогда не будет поднимать 'ActiveRecord :: Rollback'. Ну, технически Rails использует эту ошибку внутренне, но это не повысит ее в вашем транзакционном блоке. – infused