Ruby でステート マシンをマスターする:実践ガイド
ステートマシンは何かのすべての可能な状態を保持できます。 たとえば、ドアのステート マシンには 2 つの状態 (open) のみが含まれます。 および closed )、トランジションは 2 つだけ (opening) と closing ).
一方、複雑なステート マシンには、それらの間で何百もの遷移があるいくつかの異なる状態を持つことができます。実際、周りを見渡すと、ウェブサイトから買い物をするとき、自動販売機でポテトチップスのパックを買うとき、または単に ATM からお金を引き出すときでも、有限のステート マシンが周囲にあることに気づくでしょう。
この投稿では、Ruby でステート マシンをセットアップし、ステート マシン gem を使用する方法を見ていきます。
開発中のステート マシン
開発においてステート マシンが必要になるのはどのような場合ですか?簡単な答えは、状態遷移の複数のルールをモデル化したいとき、または一部の遷移で副作用を実行したいときです。ここで重要なのは、ステート マシンから恩恵を受けるアプリケーションの部分を特定することです。私にとって常に機能する良い例は、Order です。 e コマース アプリケーションのコンテキストで。
オンラインで製品を販売する単純なアプリケーションの場合、Order いくつかの状態のいずれかになります。
createdprocessingreadyshippeddeliveredvoid
次の図で、許可される遷移を確認できます。

注文をステート マシンの形式で視覚化すると、製品の注文から配送に至るまでの完全なフローを即座に明確に理解できるようになります。また、開発者にとって、フローの特定のポイントで何ができるか、何ができないかを明確に設定した手順が可能になります。
そうは言っても、これを非常に広範な問題として取り上げると、ウサギの穴に飛び降りるのは簡単で、最終的には、推論して実行するのが難しい何百もの状態が存在することになります。そのため、提案するステート マシンを実装する前に、常にそのトップレベルのアイデアと状態図を用意してください。
Ruby での最初のステート マシン
OrderStateMachine を実装してみましょう。 ルビーを使って。
これは非常に単純な実装です。ステート マシンで考えられる遷移ごとに、健全性チェックを行って遷移を実行する新しいメソッドを定義します。
上記の実装の優れた点は、すべてが明示的であることです。新しい開発者は、ステート マシンの全範囲をすぐに理解できます。
トランジションに副作用を追加する方法を見てみましょう。梱包され配達可能な注文は自動的に発送されます。
素朴な実装はうまく機能しますが、特に多くの遷移や条件がある場合、過度に冗長になります。
Ruby Toolbox を簡単にチェックすると、ステート マシン用の gem がいくつか表示されます。state_machines と aasm は最も人気のあるもので、Rails で使用する場合はどちらも ActiveRecord アダプターが付属しています。どちらも徹底的にテストされており、運用準備が整っているため、ステート マシンを実装する必要がある場合はチェックしてください。
Ruby での State Machines Gem の使用
この投稿では、Order のステート マシンをモデル化する方法について説明します。 state_machines を使用する 宝石。
上記のクラスは、単純なステート マシンとその可能なすべての遷移を定義します。これに加えて、オーダーに関する多くのユーティリティ メソッドも自動的に公開されます。
Ruby のステート マシン Gem を使用して副作用を実行する
現実世界のシステムでは通常のことですが、ステート マシンの多くの遷移には副作用が伴います。state_machines gem を使用すると、それらの定義と実行が簡単になります。2 つの副作用を追加しましょう:
ready へのすべての遷移時 、注文が deliverable の場合、配送委託品を作成します。 .fail_delivery で イベントを通知する電子メールをユーザーに送信します。通常どおり、次の順序でトランジションを実行できます。
state_machines の Github ページをチェックすることをお勧めします。 gem を参照して、gem が提供するすべての可能なオプションについて学習してください。
Ruby on Rails の ActiveRecord でステート マシン Gem を使用する
前に説明したように、両方の state_machines と aasm ActiveRecord をサポートします。state_machines を使用する場合 gem と ActiveRecord を組み合わせたものですが、実装によって多くのことが変わるわけではありません。この投稿の前のセクションですでに説明した内容のほとんどは、引き続き使用できます。
以下に追加機能をいくつか示します。
<オル>use_transactions を参照してください。 この動作を無効にしたい場合。before_transition 内でこれを行う必要があります。 callback.after_transition 内の属性を更新するには 、モデルを再度保存する必要があります。次の例を確認してください。Order.with_state(:processing) を実行できます。 すべての処理オーダーを検索するか、Order.without_state(:processing) 処理されていない注文をすべて検索します。processing から) deliveredへ )、レコードの保存に失敗し、検証エラーにエラーが追加されます。生成されたエラー メッセージを国際化するには、構成ファイル内の状態とイベントの翻訳を提供するいくつかのキーを追加するだけです(たとえば、en.yml)。 ):補足 :ActiveRecord のパフォーマンスの問題をトラブルシューティングするには、この投稿を確認してください。
まとめ:Ruby でステート マシンを構築する
この投稿では、単純なステート マシンを構築する前に、開発でステート マシンを使用する理由を検討しました。最後に、Ruby および Ruby on Rails でのステート マシン gem の使用について検討しました。
ステート マシンの基本を理解したところで、すでにステート マシンを使用している、またはステート マシンから大きな恩恵を受ける、身の回りのいくつかのシナリオに気づくでしょう。
次回まで、ステート マシンの構築が成功することを祈っています!
追記Ruby Magic の投稿を報道後すぐに読みたい場合は、Ruby Magic ニュースレターを購読して、投稿を 1 つも見逃さないようにしてください。
プルキット ゴヤル
ゲスト著者の Pulkit は、シニア フルスタック エンジニア兼コンサルタントです。自由時間には、自分の体験をブログに書いています。
Pukit Goyal によるすべての記事
-
Rubyで例外発生時にローカル変数とインスタンス変数をログに記録する方法
簡単には再現できないバグに悩まされたことはありませんか?アプリをしばらく使い続けたユーザーの環境でだけ発生し、エラーメッセージやバックトレースを見ても原因がさっぱり分からない——そんな経験を持つ開発者は多いはずです。 こうした場面で役立つのが、例外が発生する直前のアプリの状態をスナップショットとして記録しておく手法です。たとえば、すべてのローカル変数とその値の一覧を取得できれば、デバッグの強力な手がかりになります。実は、これは思ったより簡単に実現できるのです。 この記事では、例外発生時点でのローカル変数をキャプチャする方法を紹介します。ただし、最初に重要な注意点があります。ここで紹介するテ
-
【完全ガイド】Rubyの定数とは?定義方法・スコープ・注意点を徹底解説
Rubyにおける定数とは? Rubyの定数(constant)は、必ずアルファベットの大文字で始まる変数の一種です。メタプログラミングを利用しない限り、メソッドの外側でしか定義できません。 定数は「変更されるべきではない値」を扱うために用意されていますが、実はRuby自体はその変更を強制的に防ぐ仕組みを持っていません。 定数の基本的な書き方は次のとおりです: FRUIT = orange 定数はRubyプログラミングにおいて重要なトピックです。この記事では、定義方法からスコープの挙動まで、詳しく解説していきます! 定数の定義方法 定数の宣言には特別な記号や構文は必要ありません。先頭の文字を