Ruby-on-rails 如何引发 ActiveRecord::Rollback 异常并一起返回值?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1058738/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to raise an ActiveRecord::Rollback exception and return a value together?
提问by Daniel Vandersluis
I have a model that uses a acts_as_nested_setfork, and I've added a method to the model to save the model and move the node into the set in one transaction. This method calls a validation method to make sure the move is valid, which returns true or false. If the validation fails, I want my save method to raise ActiveRecord::Rollbackto rollback the transaction, but also return false to the caller.
我有一个使用acts_as_nested_setfork的模型,我在模型中添加了一个方法来保存模型并将节点移动到一个事务中的集合中。此方法调用验证方法以确保移动有效,该方法返回 true 或 false。如果验证失败,我希望我的 save 方法提升ActiveRecord::Rollback以回滚事务,但也向调用者返回 false。
My model looks like this:
我的模型看起来像这样:
class Category < ActiveRecord::Base
acts_as_nested_set :dependent => :destroy, :scope => :journal
def save_with_place_in_set(parent_id)
Category.transaction do
return false if !save_without_place_in_set
if !validate_move parent_id
raise ActiveRecord::Rollback and return false
else
place_in_nested_set parent_id
return true
end
end
end
alias_method_chain :save, :place_in_set
def validate_move(parent_id)
# return true or false if the move is valid
# ...
end
def place_in_nested_set(parent_id)
# place the node in the correct place in the set
# ...
end
end
However, when I call save in a situation that would fail, the transaction is rolled back but the function returns nil:
但是,当我在失败的情况下调用 save 时,事务会回滚但函数返回nil:
>> c = Category.new(:name => "test")
=> #<Category id: nil, name: "test" parent_id: nil, lft: nil, rgt: nil>
>> c.save_with_place_in_set 47
=> nil
>> c.errors.full_messages
=> ["The specified parent is invalid"]
回答by Shadwell
You could store the value you want returned from the function in a variable and return that outside the transaction block. E.g.
您可以将要从函数返回的值存储在变量中,然后在事务块之外返回该值。例如
def save_with_place_in_set(parent_id)
return_value = false
Category.transaction do
if !save_without_place_in_set
return_value = false
elsif !validate_move parent_id
return_value = false
raise ActiveRecord::Rollback
else
place_in_nested_set parent_id
return_value = true
end
end
return return_value
end
I've set the return_value to false initially as the only other way you can get out of that transaction block is if one of the other methods raises ActiveRecord::RollbackI believe.
我最初将 return_value 设置为 false 作为摆脱该事务块的唯一其他方法是ActiveRecord::Rollback我相信其他方法之一是否引发。
回答by Daniel Vandersluis
Because the ActiveRecord::Rollbackexception is handled, but not re-raised by ActiveRecord::Transaction, I could move my return out of the transaction block, and thus return a value after the transaction is rolled back.
因为ActiveRecord::Rollback异常被处理,但不是由 重新引发ActiveRecord::Transaction,我可以将我的返回移出事务块,从而在事务回滚后返回一个值。
With a little refactoring:
稍微重构一下:
def save_with_place_in_set(parent_id = nil)
Category.transaction do
return false if !save_without_place_in_set
raise ActiveRecord::Rollback if !validate_move parent_id
place_in_nested_set parent_id
return true
end
return false
end
回答by Matteo
I know it may be a little late, but i ran into the same problem and just found out, that within a transaction block you can simply raise an Exception and rescue that one...Rails implicitly rollbacks the whole transaction. So there is no need for ActiveRecord::Rollback.
我知道现在可能有点晚了,但我遇到了同样的问题,并且刚刚发现,在事务块中,您可以简单地引发一个异常并挽救那个异常……Rails 隐式地回滚整个事务。所以不需要 ActiveRecord::Rollback。
For example:
例如:
def create
begin
Model.transaction do
# using create! will cause Exception on validation errors
record = Model.create!({name: nil})
check_something_afterwards(record)
return true
end
rescue Exception => e
puts e.message
return false
end
end
def check_something_afterwards(record)
# just for demonstration purpose
raise Exception, "name is missing" if record.name.nil?
end
I'm working with Rails 3.2.15 and Ruby 1.9.3.
我正在使用 Rails 3.2.15 和 Ruby 1.9.3。

