9

コントローラのアクションの例があります。

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'

Controllersでトランザクションを使用することは悪い習慣ですが、その理由はわかりません(http://markdaggett.com/blog/2011/12/01/transactions-in-rails/

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

ありがとう。

4

1 に答える 1

25

本当に必要な場合は、コントローラーでトランザクションを使用できます。お気づきのとおり、これは悪い習慣ですが、やりたい場合は、のProduct.transaction do代わりに電話してくださいtransaction dotransactionはのクラスメソッドでActiveRecord::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_timeclientそのメソッドにも渡す必要があるかもしれません。コードからどこclientから来たのかは不明です。の属性の場合product、上記の方法が機能するはずです。

これを行うためのより良い、より多くのRailsyの方法もあります。特に、コントローラーデータを必要とせずにproductそれについて知っている場合はそうです。client次に、次のようにコールバックを使用できます(クラスafter_saveに追加)。Product

after_save :update_client

private

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

その後、aが保存されるたびProductに、関連付けられたクライアントのフィールドが更新されます。client最初のコードが存在するかどうかを確認するために、コードを導入する必要があるかもしれません。

よりクリーンなコードに加えて、コールバックを使用する利点は、コールバックチェーン全体が保存とともに単一のトランザクションで実行されることです。トランザクションを手動で作成する必要はありません。Railsのドキュメントでコールバックの詳細を読むことができます。

于 2013-03-27T13:13:55.473 に答える