2013-03-27 15 views
9

私はコントローラにアクションの例があります。RAILS 3 - コントローラ内のトランザクション

def some_action 
product = Product.new 
product.name = "namepro" 
    if product.save 
    client.update_attribute(:product_id,product.id) 
    end 
end 

このコードのトランザクションを追加するにはどうすればよいですか?私は、この例のコードで試してみてください。

def some_action 
**transaction do** 
    product = Product.new 
    product.name = "namepro" 
    if product.save 
    client.update_attribute(:product_create,Time.now) 
    end 
**end** 
end 

しかし、それは、このエラーを生成します。

undefined method `transaction' 

私はコントローラにトランザクションを使用して読ん悪い習慣ですが、その理由(http://markdaggett.com/blog/2011/12/01/transactions-in-rails/ですなぜ私は知りません)

この例では、製品が作成され、保存され、クライアントの更新に失敗した場合... Railsは何もしてはいけません。

ありがとうございました。

答えて

25

本当にしたい場合は、コントローラでトランザクションを使用することができます。あなたが指摘したように、それは悪い習慣ですが、それをしたい場合はtransaction doの代わりにProduct.transaction doと呼んでください。 transactionActiveRecord::Baseのクラスメソッドなので、ActiveRecord派生クラスで呼び出す必要があります。アプリケーションのすべてのモデルクラスが行います(ニトロピッキングの注意点:異なるモデルの異なるデータベースに接続している場合はそうでないかもしれませんが、おそらくそれはしません)。

これは悪い習慣である理由は、それがMVCのパラダイムに従って懸念を適切に分離しないためです。あなたのコントローラーはあなたのデータ永続化の実装にあまり関心を持ってはいけません。より良い方法は、Productにメソッドを追加することです。たぶん、このような何か:

def save_and_update_create_time 
    transaction do 
    if save 
     client.update_attribute(:product_create, Time.now) 
    end 
    end 
end 

そして、代わりにあなたのコントローラでproduct.saveを呼び出す、product.save_and_update_client_create_timeを呼び出します。その方法にclientを渡す必要があるかもしれません。あなたのコードからは、clientがどこから来るのかは不明です。 productの属性の場合は、上記の方法が有効です。

コントローラのデータを必要とせずに、productがそのclientを知っている場合は、これを行うためのより良い、より多くのRailsの方法があります。

after_save :update_client 

private 

def update_client(product) 
    product.client.update_attribute(:product_create, Time.now) 
end 

その後Productが保存されるたびに、関連するクライアント上のフィールドが更新されます。次に、あなただけのこの(Productクラスに追加)のように、after_saveコールバックを使用することができます。おそらく最初にclientの存在を確認するコードを導入する必要があります。

クリーンなコードのほかに、コールバックを使用する利点は、コールバックチェーン全体がsaveとともに単一のトランザクションで実行されることです。トランザクションを手動で登録する必要はありません。コールバックについて詳しくはRails documentationをご覧ください。

+0

おかげでジム、本当にあなたの説明で私を助けて! – user1364684

+3

トランザクションロジックをモデルに入れると、トランザクションは1つのモデルに限定されず、別の懸念ルールを破らないでしょうか?通常、トランザクションは複数のモデルにまたがる可能性が高く、DBレベルでは必ずしも互いに関連しているとは限りません。 – xSNRG

+1

ええ、私は私のコメントのその特定の側面に心の変化をもたらしました。私はそれをコントローラーから外すという考えが好きですが、複数モデルのやりとりはどこかにラップされるべきです。たぶん別のクラスかもしれませんが、状況によってはコントローラーが正しい場所になっているかもしれません。 –

関連する問題