2010-02-11 87 views
11

我有兩種模式:用戶和公司。他們都得到從一種形式創建,我使用的是交易是這樣的:即使公司的驗證的一個失敗Rails事務不驗證錯誤回滾

User.transaction do 

    @user.save! 

    @company.user = @user 
    @company.save! 

    @user.reload 
    @user.company = @company 
    @user.save! 

flash[:notice] = "Thank you for your registration." 
    redirect_to_index 
end 

用戶獲取保存到數據庫中。我已經嘗試添加ActiveRecord :: RecordInvalid的顯式錯誤處理,但它沒有幫助。我認爲驗證會導致無論如何回滾事務的錯誤。任何幫助是極大的讚賞。

感謝

+10

您使用的是什麼RDBMS?它支持事務(MyISAM vs InnoDB)嗎? – 2010-02-11 16:49:51

+0

啊,我想就是這樣。大多數表是innoDB,但有一些myisam。謝謝 – Shagymoe 2010-02-11 16:59:12

+0

參見http://stackoverflow.com/questions/2481806/how-do-i-get-save-no-exclamation-point-semantics-in-an-activerecord-transaction – 2010-04-07 22:30:16

回答

-2

http://tempe.st/2007/05/transaction-in-rails/

我相信你必須使用一個開始交易外循環結束塊。

+0

不正確。如果你想做的不僅僅是一個簡單的回滾,你需要一個''''''rescue''''end'塊,但是堆棧上方的異常處理器可以在回滾之後輕鬆地處理它完成。你也可以讓Rails處理它並顯示一個錯誤頁面。 – 2010-03-29 15:04:02

0

你將不得不考慮這些情況

  1. 使用支持交易
  2. 重因子數據庫系統,它更符合邏輯的做法

作爲示例代碼,如果你只有一對一的關係,可以更優化地處理它

Company has_one User 
User belongs_to Company 

現在,在公司模型

@company.user.build(user_attributes) 
@company.save # will save company as well as user 

我還沒有測試它作爲一個例子。就在我的腦海裏。 我是否正確理解問題?

2

您必須使用支持ACID事務的數據庫引擎。對於INNODB的mysql。

show table status\G 

如果用戶或公司是使用InnoDB引擎,你可以改變它瓦特/此命令。

ALTER TABLE <table name> ENGINE INNODB; 

@company.save! *拋出應觸發ROLLBACK命令異常將被髮送到數據庫。您可以在運行具有DEBUG日誌級別的腳本/服務器時在控制檯/日誌文件中驗證這一點。

+0

不要在事務內部捕獲ActiveRecord :: RecordInvalid異常,因爲此異常會使某些數據庫(如Postgres)上的事務無效。一旦事務失效,您必須從頭開始重新啓動它才能正常工作。 http://markdaggett.com/blog/2011/12/01/transactions-in-rails/ – macsig 2013-01-19 10:06:01

0

save()和destroy()總是處於事務中(請參閱http://railsapi.com/doc/rails-v2.3.5/classes/ActiveRecord/Transactions/ClassMethods.html)。

我想你想要做的是

begin 
    @company = Company.create!(params[:company]) 
    @user = User.create!(params[:user]) { |user| user.company => @company } 
    rescue => ex 
    # ... handle your validation errors 
    end 

當公司驗證失敗的,將引發異常和User.create語句根本不會執行這將解決您的問題。

1

嘗試保存新條目並同時修改現有條目(基於新條目),則遇到類似問題。試圖與救援失敗的交易驗證,但在此解決:代替

if @new_entry.valid? && @existing_entry.valid? 
    ActiveRecord::Base.transaction do 
    @new_entry.save! 
    @existing_entry.save! 
    end 
end 

代碼首先驗證。它不會嘗試保存,除非兩個條目都有效。如果數據庫支持,則事務語義防止其他錯誤上的不完整條目。希望這是一個很好的解決方案。