2011-06-13 15 views
2
class Bear < ActiveRecord::Base 
    def feed! 
     self.transaction do 
      raise Exception unless self.foods_eaten << Food.new(:name => "fish") 
      self.fed_at = Time.now 
      save! 
     end 
    end 
end 

class Hippo < ActiveRecord::Base 
    def wash! 
     self.transaction do 
      @soap.inventory -= 1 
      @soap.save! 
      self.washed_at = Time.now 
      save! 
     end 
    end 
end 

class ZookeeperController < ApplicationController 

    def chores 
     @zookeeper = Zookeeper.find(params[:id]) 
     Animal.transaction do 
      begin 
       @hippo.wash! 
       @bear.feed! # => FAIL AT THIS LINE 
       @zookeeper.finished_at = Time.now 
       @zookeeper.save! 
       redirect_to chores_completed_path 
      rescue Exception => e 
       render "new_chores" 
      end 
     end 
    end 
end 

如果Zookeeper#chores被調用且@bear.feed!失敗並引發異常,那麼將所有的回滾?Rails 3 Transactions,回滾一切

對於如何改進此代碼的任何其他建議也是受歡迎的。

+0

我使用MySQL 46年1月5日,Rails的3.0.8和Ruby 1.9.2 – Dex 2011-06-15 02:43:16

回答

4

看來我必須做的是手動引發ActiveRecord :: Rollback,否則它將無法按預期工作。 ActiveRecord ::回滾是唯一一個不會導致你的屏幕轉儲。 http://api.rubyonrails.org/classes/ActiveRecord/Rollback.html

它是有道理的,它會這樣工作,但不是真的我直覺上認爲它會工作。如果我錯了,請糾正我。

因此,新的代碼將是這個樣子:

class ZookeeperController < ApplicationController 

    def chores 
     @zookeeper = Zookeeper.find(params[:id]) 
     Animal.transaction do 
      begin 
       @hippo.wash! 
       @bear.feed! # => FAIL AT THIS LINE 
       @zookeeper.finished_at = Time.now 
       @zookeeper.save! 
       redirect_to chores_completed_path 
      rescue Exception => e 
       @_errors = true 
       render "new_chores" 
      end 
      raise ActiveRecord::Rollback if @_errors 
     end 
    end 
end 
+0

我只是好奇,這實際上可以作爲你的預期。當你在救援塊中調用渲染時,它不會結束'chores'動作,並且永遠不會使它進入'ActiveRecord :: Rollback'? – Joey 2011-09-13 07:18:36

+1

我還建議將動物事務中的所有內容重構爲模型實例方法,如'do_chores!'返回true或false,並在您的控制器中調用'if @ zookeeper.do_chores!'來決定下一步發送用戶的位置。 – Joey 2011-09-13 07:25:35