2009-06-29 57 views
22

我有一个使用叉的acts_as_nested_set模型,并且我在模型中添加了一个方法来保存模型并将节点移动到一个事务中的集合中。此方法调用验证方法以确保移动有效,并返回true或false。如果验证失败,我希望使用我的保存方法提高ActiveRecord::Rollback以回滚事务,但也会将错误返回给调用者。如何引发ActiveRecord :: Rollback异常并返回一个值?

我的模型看起来是这样的:

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 

然而,当我打电话保存在会失败的情况下,该事务回滚,但该函数返回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"] 

回答

26

您可以保存您想从功能的变量返回的值,并返回该事务块之外。例如。

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 

我已经设置了RETURN_VALUE为false最初,你可以得到的是事务块的唯一另一种方式是,如果其他方法人提出ActiveRecord::Rollback我相信。

+0

+1,我得出的结论基本相同。 – 2009-06-29 15:24:27

10

因为ActiveRecord::Rollback异常被处理,但不会被ActiveRecord::Transaction重新提出,我可以将我的返回移出事务块,并在事务回滚后返回一个值。

随着一点点的重构:

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 
-1

我知道它可能有点晚,但我遇到了同样的问题,只是发现,在一个事务块内,你可以简单地提出一个异常并拯救那个...... Rails隐式地回滚整个事务。所以不需要ActiveRecord :: Rollback。

例如:

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 

我使用Rails 3.2.15和Ruby 1.9.3工作。