2009-06-29 87 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工作。