Appointment Reminders with Ruby and Rails
アプリケーションにアポイントメントリマインダーを実装する準備はできましたか?アポイントリマインダーが高レベルでどのように機能するのかを以下に示します。
- 管理者は、将来の日時に対するアポイントメントを作成し、そのアポイントメント用に顧客の電話番号をデータベースに保存します。
- バックグラウンドプロセスは、データベースを定期的にチェックし、リマインダーを送信する必要があるアポイントメントを探します。
- アポイントメントより前の設定済み時間に、アポイントメントを思い出させるために SMS リマインダーが顧客に送信されます。
ビルディングブロック
これを行うために使用するテクノロジーは以下のとおりです。
- Ruby on Rails:データベースドリブンのウェブアプリケーションを作成します。
- Messages Resource:Twilio の REST API からテキストメッセージを送信します。
- Delayed::Job:バックグラウンドタスクを繰り返しスケジュールおよび実行できるようにします。
このチュートリアルの読み方
アポイントメントリマインダーを実装するために、アポイントメントリマインダーをウェブアプリケーションに完全に実装する方法を示した一連のユーザーストーリーに取り組みます。各ストーリーを実現するために必要なコードを一通り確認し、各ステップで何を追加する必要があるのかを説明します。
これはTwilioの助けを借りれば30分以内で完了できます。
アポイントメントの作成
ユーザーとして、名前、ゲスト電話番号、および将来の時間を使ってアポイントメントを作成します。
自動アポイントメントリマインダーアプリケーションを構築するには、ほとんどの場合アポイントメントから始めます。このストーリーでは、システムで新しい Appointment
を作成および保存するために、UI およびモデルオブジェクトを多少作成する必要があります。追加する必要があるのは、おおまかに以下のとおりです。
- アポイントメントに関する詳細を入力するためのフォーム
- フォームをレンダリングするためのサーバー上のルートおよびコントローラー関数
- フォーム POST リクエストを処理するためのサーバー上のルートおよびコントローラー関数
- ユーザーに関する情報を保存するための永続的な
Appointment
モデルオブジェクト
まず始めに、モデルを見てみましょう。モデルでは、アポイントメントと共に保存する情報を決定します。
Rails ジェネレーター
通常、チュートリアルのこのポイントでは、モデル、ビュー、およびコントローラーを一から構築します(例としてアカウント認証を参照)。ただし、アポイントメントモデルは非常に明快であり、実際に必要なのは基本的な CRUD スキャフォールディングのみであるため、今回に限り Rails ジェネレーターを使用します。
ツールに関する注意事項
このアプリケーションでは Rails 4 を使用していますが、3 以下の場合でも、アプリケーションはほぼ同じになります。また、twilio-ruby ヘルパーライブラリも使用しています。最後に、ブートストラップを使用して設計を簡単化します。このケースでは、twitter-bootstrap-rails というブートストラップをテーマにしたビューを生成する gem があります。機会があれば、これらのツールを調べてください。では、スキャフォールディングの生成に進みましょう。
モデル、ビューおよびコントローラーの生成
Rails generate は、モデル、ビュー、テストなどの rails コンポーネントを生成するコマンドラインツールです。このチュートリアルでは、重要な役割を担うジェネレーター(scaffold
)を使用して、すべてのものを一度に生成します。
その方法は次のとおりです。rails アプリケーション内から、以下を実行しました。
$ bin/rails generate scaffold Appointment name:string phone_number:string time:datetime
これは、Appointment というリソース用のスキャフォールディングを作成するようにジェネレーターに伝えます。Appointment には、name、phone_number、および time プロパティがあります。
次に、生成されたモデルに進んで、要素をいくつか追加してみましょう。
アポイントメントモデル
アポイントメントモデルは、追加設定なしの非常にシンプルなものですが、人間がかかわるので、データ検証を追加しておきましょう。
データ検証
正確なデータだけがデータベースに確実に保存されるようにしたいため、検証は重要です。今回は、すべての必須フィールドが存在することを検証するだけにとどめます。これを行うには、presence: true
を使用して validates
文を作成します。
アポイントメントモデルは、アポイントメントの現場で管理者が作成する可能性があります。アポイントメントの作成時にフィードバックを admin ユーザーに提供できたら便利です。幸いなことに、Rails では、モデルに検証を追加した場合、セッションの flash
オブジェクトを使って無料でエラーがレポートされます。
注:このデモを実行するためには、db/migrate フォルダーでマイグレーションを実行する rake db:migrate
を実行する必要があります。このチュートリアルでは、中心概念に焦点を当てますが、マイグレーションについて詳しく学びたい場合は、そのサブジェクトに関する Rails ガイドをお読みください。
これで、アプリケーションのコントローラーレベルに移動して必要な HTTP リクエストルートから始める準備ができました。
ルート
Rails アプリケーションでは、Resource Routing はリソースの CRUD 機能をコントローラーに自動的にマップします。Appointment
は ActiveRecord リソースであるため、これらのルートを使用することを単に Rails に伝えることができます。これにより、数行のコードが節約されます。
つまり、この 1 行のコードでは、appointment/new.html.erb
ファイルを自動的にレンダリングする appointment/new
ルートを自動的に持ちます。
このフォームを詳しく見てみましょう。
新規アポイントメントフォーム
新しいアポントメントを作成する際は、ゲスト名、電話番号、時刻が必要です。rails form_for
タグを使って、 モデルオブジェクトにフォームをバインドできます。これにより、必要な html マークアップが生成され、送信時に新しいアポイントメントが作成されます。
モデルにバインドされたフォーム用に Rails が提供する特定のヘルパータグに注目してみましょう。
日付と時刻
アポイントメントの日付と時刻の処理方法を見つけ出すのは、時間の浪費を招く可能性がある作業の 1 つです。実際には、これは 2 つの独立したユーザー入力です。1 つはアポイントメントの日付、もう 1 つはアポイントメントの時刻です。この 2 つの独立した入力をサーバー側で 1 つのパラメーターにまとめる方法が必要です。Rails は、これを処理するために、data_select
および time_select
タグを提供します。サーバーは、appointment.time
プロパティにマップされる 1 つのパラメーターにこれらのタグを自動的に収集します。
コントローラーに戻って、このアポイントメントの作成時に何が起こるのかを見てみましょう。
Handle the Form POST
Appointment
リソースルートによって作成された他の便利なコントローラーの 1 つは、フォームから POST を処理する appointment/create
でした。
コントローラーでは、フォームから入力を取得し、新しい Appointment
モデルを作成します。アポイントメントがデータベースに正常に保存された場合は、アポイントメント詳細ビューにリダイレクトします。このビューは、新しいアポイントメントを作成者に表示し、そのアポイントメントの編集や削除を作成者に許可します。
次に、編集および削除用に生成されたコントローラーを見てみましょう。
アポイントメントとのインタラクション
ユーザーとして、今後のすべてのアポイントメントのリストを表示するとともに、 これらのアポイントメントを削除できるようにします。
大量のアポイントメントを扱う組織の場合は、おそらくそれらのアポイントメントを単一のインターフェイスで表示および管理できるようにしたいと考えるでしょう。このユーザーストーリーでは、それに取り組みます。以下の操作を行う UI を作成します。
- すべてのアポイントメントを表示する
- 個々のアポイントメントを削除する
まず始めに、コントローラーを見てみましょう。
Show a List of Appointments
コントローラーレベルでは、データベース内のすべてのアポイントメントのリストを取得し、ビューでレンダリングします。また、このデモは将来のアポイントメントが 1 つ以上存在することを前提としているため、アポイントメントがない場合はプロンプトを追加する必要があります。
テンプレートに戻って、アポイントメントのリストを見てみましょう。
すべてのアポイントメントの表示
インデックスビューには、すべてのアポイントメントがリストされ、自動的に date_created
によって順序付けられます。ユーザーストーリーを全うするのために追加が必要なのは、削除ボタンだけです。 余興として編集ボタンも追加しましょう。
URL ヘルパー
編集および削除用の URL をハードコードするのではなく、Rails URL ヘルパーを使うことに注意してください。レンダリングされたマークアップを表示する場合は、このパスを参照します。
/appointments/
ID
/edit
(編集の場合)/appointments/
ID
(削除の場合)、HTTP DELETE メソッドがクエリーに追加されている状態
これらの URL ヘルパーは、アポイントメントオブジェクトまたは ID を取得できます。
There are some other helpers in this code that Rails generates for us. The one I want to point out is the :confirm
tag. The confirm tag is a data attribute that interrupts the actual DELETE
request with a javascript alert. This is best-practices when calling DELETE
on an object. If the user confirms we process the request normally, otherwise no action will be taken.
Now let's take a look at what happens in the controller when we ask to delete an appointment.
Look up an Appointment
このコントローラーでは、アポイントメントレコードを引き出して削除する必要があります。まず、どのようにアポイントメントを取得するのかを見てみましょう。
ほとんどのビューでアポイントメントレコードが必要になると思われるため、複数のコントローラー間で共有できるプライベートインスタンスメソッドを作成する必要があります。
set_appointment
では、ルートから渡された id パラメーターを使用して、アポイントメントを検索します。次に、以下のようにコントローラーの一番上で before_action
フィルターを使用します。
before_action :set_appointment, only: [:show, :edit, :update, :destroy]
これは、どのコントローラーにこのフィルターが適用されるのかをアプリケーションに伝えます。このケースでは、コントローラーが単一のアポイントメントを処理する場合にのみアポイントメントが必要になります。
次に、アポイントメントが実際に削除されたときに何が起こるのかを見てみましょう。
Delete an Appointment
アポイントメントが見つかったので、そのアポイントメント上で単に .destroy
を呼び出します。プロダクションアプリでは、場合によっては、destroy の代わりに .delete
を使用するかどうかを評価する必要があります。これは、どちらも Rails でデータベース行を削除するのに有効な方法だからです。このチュートリアルでは、以下の 2 つの理由により、効率性で劣る destroy の方を使用します。
- データベースクリーンアップを処理する
- It keeps the
Appointment
in memory, so that we can flash a success message to the user
アポイントメントと情報を交換できるようになったので、これらのアポイントメントのいずれかが発生する際にリマインダーを送信してみましょう。
Send the Reminder
アポイントメントシステムとして、今後のアポイントメントの前に、任意の間隔で SMS を介してユーザーに通知します。
アプリケーションのこの部分を構築する方法は数多くありますが、その実装方法に関係なく、2 つの可動部分が存在する必要があります。
- 近く予定されているアポイントメントがないかデータベースをチェックした後、sms を送信するスクリプト
- このスクリプトを連続して実行するワーカー
Let's take a look at how we decided to implement the latter with Delayed::Job
.
Delayed::Job の操作
前に述べたように、スケジューラー/ワーカーの実装方法は数多くありますが、Rails Delayed::Job
が最も定評があります。
Delayed Job では、近く予定されているジョブのキューを作成するために、何らかの類のバックエンドが必要です。ここでは、delayed_job の ActiveRecord アダプターを追加しました。このアダプターは、データベースを使用して 'Jobs' データベースを保存します。サポートされているバックエンドは数多くあるため、適正な gem をアプリケーションに使用してください。
gem を含めたら、bundle install
を実行し、次に rake タスクを実行してデータベースを作成する必要があります。
rails g delayed_job:active_record
これらの手順は、このプロジェクトの github repo で確認できます。
これで、実際のジョブを作成する準備ができました。
リマインダーを送信する
ユーザーにリマインダーを送信するための次のステップは、アポイントメント時間の前に特定の間隔で起動するスクリプトの作成です。最終的にはアポイントメントの作成時にこのリマインダーをスケジュールしたいため、Appointment モデル上のメソッドとしてリマインダーを記述するのが理にかなっています。
最初に、Twilio REST API によって SMS を送信する Twilio クライアントを作成します。Twilio クライアントを作成するには、以下の 3 つのものが必要になります。
- Twilio アカウント SID
- Twilio Auth Token
- テキストメッセージを送信できるアカウント内の Twilio 番号
All of these can be found in your console.
sms を送信するために次に行うべきことは、組み込みの messages.create()
を使用して SMS をユーザーの電話に送信することです。
モデルコールバック
リマインダースクリプトをモデル上のメソッドにしたため、コールバックという非常に便利なツールを手に入れました。before_create
コールバックを使用することにより、リマインダーは Appointment が作成されるたびに確実に呼び出されます。
最後のステップでは、このコールバックが最終的に Delayed Job によって必ずスケジュールされるようにします。
Schedule a Reminder
もうすぐ終わりですが、ここでは以下の操作を行う非常に複雑なスケジュールコントローラーを記述する必要があります。
- 今後の各アポイントメントを検索する
- そのアポイントメントを Jobs テーブルに追加する
- そのアポイントメントが
minutes_before_appointment
間隔内にあるかどうかをチェックする - リマインダーメソッドを起動する
Delayed Job は、これを handle_asynchronously
という便利なメソッドで無償で行います。このメソッドは、起動されるたびに、このジョブをスケジュールするように Delayed Job に伝えます。ジョブ時間は個々の Appointment instance
に依存するため、その時間を計算する関数を handle_asynchronously
メソッドに渡す必要があります。このケースでは、minutes_before_appointment
は 30 分に設定されますが、任意の Time
間隔を使用できます。
アポイントメントを作成すると、時間および起動すべきメソッドと共に Jobs テーブルに新しい行が表示されます。また、delayed_job はエラーを保存し、失敗する前に不具合をデバッグできるようにします。delayed_job は、ジョブを起動すると、データベースからそのジョブを削除します。そのため、適切な日に空のデータベースを見ることになります。
All Done
それは大仕事でしたが、実際には非常に小さなコードを記述して、自動アポイントメントリマインダーを Twilio で起動させる必要がありました。
次はどこでしょうか?
多少のコードとわずかな設定で、自動アポイントメントリマインダーをアプリケーションで起動できます。お疲れ様でした。
If you are a Ruby developer working with Twilio, you might want to check out other tutorials in Ruby:
ウェブページのボタンを押して、電話を介して訪問者をライブサポートまたはセールス担当者に接続します。
Improve the security of your Ruby app's login functionality by adding two-factor authentication via text message.
これは役に立ちましたか?
Thanks for checking out this tutorial! If you have any feedback to share with us, please reach out on Twitter... we'd love to hear your thoughts, and know what you're building!
ヘルプが必要ですか?
誰しもが一度は考える「コーディングって難しい」。そんな時は、お問い合わせフォームから質問してください。 または、Stack Overflow でTwilioタグのついた情報から欲しいものを探してみましょう。