2011-06-13 3 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!이 실패하고 예외가 발생하고 모든 롤백 할 것인가?레일 3 트랜잭션, 롤백 모든

이 코드를 향상시키는 방법에 대한 다른 제안도 환영합니다.

+0

을 예상대로이 실제로 작동하는 경우 3.0.8와 루비 1.9.2 – Dex

답변

4

ActiveRecord :: Rollback을 수동으로 발생시키는 것 같습니다. 그렇지 않으면 예상대로 작동하지 않습니다. ActiveRecord :: Rollback은 화면을 덤프하지 않는 유일한 것입니다. http://api.rubyonrails.org/classes/ActiveRecord/Rollback.html

그것이 이와 같이 작동한다는 것은 의미가 있지만 실제로 직감적으로 어떻게 작동 할 것이라고 생각했는지는 알 수 없습니다. 내가 틀렸다면 나를 바로 잡아주세요.

그래서 새로운 코드는 다음과 같이 보일 것이다 : 나는 MySQL은 5.1.46을 사용하고

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

+1

또 Animal 트랜잭션 내부의 모든 것을'do_chores! '와 같은 모델 인스턴스 메소드로 리팩터링하여 true 또는 false를 반환하고 컨트롤러에서'if @ zookeeper.do_chores!'를 호출하여 다음에 사용자를 보낼 위치를 결정할 것을 제안합니다. – Joey