Ruby
 Computer >> コンピューター >  >> プログラミング >> Ruby

Ruby on Rails トランザクションをマスターする:5 つの基本的な設計プラクティス

データの整合性の問題は、Rails 開発者が直面する最も一般的なデータベースの問題の 1 つです。適切な検証が可能になるだけでなく、正しく設計されたトランザクション ブロックにより、データが部分的に作成または更新されないことが保証されます。

ただし、適切に設計されていない場合、トランザクションはアプリケーションに損害を与えたり、データベース全体をダウンさせたりする可能性もあります。

この記事では、トランザクションを操作するための一連の優れたプラクティスを紹介します。ヒントは非常にシンプルですが、トランザクションを完全に防止し、読みやすく、比較的安全にするのに役立ちます。

さあ、飛び込んでみましょう!

1.可能な場合はレールで Bang メソッドを使用する

Rails では、! を持つメソッドのバージョン 何か問題が発生したときにエラーが発生するという確信を与えることができます。

たとえば、#save このメソッドは save! にも存在します。 バージョン。エラーを発生させたくない場合は、コントローラでこのバージョンを使用するとよいでしょう。

 

上記のアプローチはトランザクションではうまく機能しません。 save を使用する 、エラーが発生したときにプロセスをロールバックすることはできません。そのため、! を使用することが非常に重要です。 メソッドのバージョン:

 

上記では、メンバーシップ レコードが作成されていなくてもトランザクションは成功し、データベース内のデータ構造が混乱してしまいます。

次のバージョンを使用すると、ActiveRecord::RecordNotSaved によりトランザクションが元に戻ります。 エラー:

 

2. Rails トランザクションのエラーを適切に処理する

トランザクションでのエラーに関しては、尊重する必要があるルールがいくつかあります。これらのルールに従うことで、他の開発者の間で混乱が生じたり、デバッグが難しい奇妙な動作が発生したりすることのない、読みやすく適切に機能するコードが得られます。

ActiveRecord::StatementInvalid から救出しないでください

ActiveRecord::StatementInvalid データベース レベルで何か問題が発生した場合に発生する特別なエラーです。このエラーからは絶対に救出しないでください。データベース クエリで問題が発生した場合は、常に明示的に通知される必要があります。

次のコードは避けてください:

 

適切なレベルでレスキューを使用する

次のレベルでレスキューを使用すると、エラーが発生します:

 

エラーが発生したため、トランザクションはロールバックされません。エラーを発生させて、トランザクション ブロックの外でキャッチします。

 

上記のアプローチでは、エラーが発生した場合にトランザクションがロールバックされ、エラーをキャッチします。これは、トランザクションの動作を上書きせずに、トランザクション内で発生したエラーを捕捉するための正しいアプローチです。

一般的なエラーをキャッチしない

StandardError のような一般的なエラーを検出しないようにする必要があります。 または ArgumentError 。これは、読みやすくテストしやすいコードのための一般的なルールに近いものですが、言及する価値はあります。

コード内の他の場所でエラーが発生する可能性があるため、これらのエラーを検出するとデバッグが困難になる可能性があります。これにより、アプリ内で、必ずしも救出場所とは関係のない重大な問題が発生する可能性があります。

ActiveRecord のデフォルトのロールバック エラーを賢く使用する

ActiveRecord は、サイレント ロールバックを行うためにトランザクション内で使用できる特定のエラー クラスを提供します。 ActiveRecord::Rollback を発行すると、トランザクションをロールバックできます。 エラーですが、他のエラーのように、エラーは外部で発生しません。この動作を念頭に置いて、賢明に使用してください。

3. Rails でトランザクションの使用を避けるべき場合を知る

他のものと同様に、コード内でトランザクションを過度に使用しないでください。たとえば、よくある間違いは、トランザクションにクエリを 1 つだけラップすることです。クエリが成功しなかった場合、何もロールバックする必要がないため、これは意味がありません。

もう 1 つのよくある間違いは、データベース呼び出しに関係のないコードをトランザクションにラップすることです。ブロック内のコードが実行されない限り、トランザクションは接続を保持するため、このようなアプローチは避けてください。可能であれば、ブロック内のコードをデータベースのみを呼び出すように制限してください。

4.トランザクションのデメリットを理解する

トランザクションはデータベース内のデータの整合性を維持するのに役立ちますが、その欠点にも注意する必要があります。たとえば、トランザクション ブロックでラップされたクエリは、単一のクエリよりも多くの DB リソースを必要とします。

トランザクションを使用する場合のもう 1 つの欠点は、コードがより複雑になることです。トランザクションを誤って使用すると、コードが読みにくくなる可能性があります。

5.適切なコンテキストでトランザクション ブロックを使用する

クラスが ActiveRecord から継承する場合、トランザクション メソッドを使用できます。 クラス。これは、使用するバージョンが重要ではないという意味ではありません。機能の観点からは重要ではないかもしれませんが、コードを読みやすくするという観点からは重要です。

3 つの一般的なバージョンでは、トランザクション メソッドが使用されます。

 

多くのモデルを使用し、ブロック内のクラスとインスタンス メソッドの呼び出しを混在させる場合は、ActiveRecord::Base.transaction を使用する必要があります。 :

 

特定のモデルに属するコードを主に扱う場合は、クラスでトランザクション メソッドを呼び出します。

 

モデル インスタンスを操作する場合、インスタンス レベルでトランザクション メソッドを呼び出すことが合理的です。

 

もちろん、これらのルールは正式なものではありません。これらは、コードを読みやすくするための単なる提案です。

次のステップ:Ruby on Rails プロジェクトのトランザクションを確認する

Ruby on Rails でトランザクションを操作するためのこれらのヒントがお役に立てば幸いです。

データの整合性を向上させ、予期せぬ副作用なしにプロセスが確実に実行されるようにするために、Rails トランザクションを適切に設計することの重要性について説明しました。

ただし、適切なエラー処理ポリシーは、トランザクションを使用する場合に有益であるだけでなく、コードベース全体の改善にも役立ちます。次回コードでエラーが発生すると予想される場合は、このことを念頭に置いてください。

エラーを避けるために、Ruby on Rails プロジェクト設計のトランザクションを確認する絶好の機会です。データベースとの効率的かつ信頼性の高い通信を設計して、アプリケーションをより安定させます。

コーディングを楽しんでください!

追記Ruby Magic の投稿を報道後すぐに読みたい場合は、Ruby Magic ニュースレターを購読して、投稿を 1 つも見逃さないようにしてください。

Ruby on Rails トランザクションをマスターする:5 つの基本的な設計プラクティス

パヴェウ ドンブロフスキ

私たちのゲスト著者である Paweł は、オープンソースのファンであり、成長を求める人であり、人間とコンピューターの両方について 10 年以上の執筆経験があります。彼は点と点を結びつけて高品質のソフトウェアを作成し、人々や企業との貴重な関係を構築します。

Paweł Dąbrowski によるすべての記事


  1. Rubyのカスタム例外

    Rubyで独自の例外を作成するのは簡単です。次の手順に従ってください: 1。新しいクラスを作成する 例外は、Rubyの他のすべてと同じように、クラスです。新しい種類の例外を作成するには、StandardErrorまたはその子の1つから継承するクラスを作成するだけです。 class MyError < StandardError end raise MyError 慣例により、新しい例外のクラス名は「エラー」で終わります。カスタム例外をモジュール内に配置することもお勧めします。つまり、最終的なエラークラスは次のようになります:ActiveRecord::RecordNotFound

  2. メタプログラミングの隠れたコスト

    メタプログラミングは非常に派手な言葉のように聞こえますが、それは何か良いことですか? 便利な場合もありますが、メタプログラミングの使用にはいくらかのコストがかかることに多くの人が気づいていません。 同じページにいるので… メタプログラミングとは 正確に? 私はメタプログラミングを次のような方法を使用するものとして定義しています: コードの構造を変更します(define_methodなど) ) 文字列を実際のRubyコードの一部であるかのように実行します(instance_evalなど)。 ) 何らかのイベントへの反応として何かを行います(method_missingなど) ) で