[coreserve]予約とキャンセル
一番重要な予約とキャンセルの処理を実装しました。
実際の作業は、(いろいろな割り込みもあったので)もうちょっと行きつ戻りつしていますが、基本的にはテストを書いて実装して、Webrickサーバで動かして調整しての繰り返しでやりました。
まず、ログインしてからの一覧表示のテスト。ここで作成したfixtureを使用しています。
def test_index_for_client get :index, {}, :user=>@cl1 assert_response :success # ログアウトへのリンクを表示しているか assert_tag 'a', :attributes => { :href => '/client/logout' } # 空きデータを表示しているかメモ欄のテキストで確認 assert_match /free1/, @response.body assert_match /free2/, @response.body # 予約済データを表示しているかメモ欄のテキストで確認 assert_match /reserved1/, @response.body # コントローラの変数に設定された空きデータの件数確認 assert_equal 3, assigns("counseling_sessions").size # コントローラの変数に設定された空きデータのステータス確認 assigns("counseling_sessions").each do |c| assert((c.status == :reserved and c.client == @cl1) || (c.status == :free )) end # 予約へのリンクがあるか assert_tag 'a', :attributes => { :href => '/main/reserve/10001' } assert_tag 'a', :attributes => { :href => '/main/reserve/10002' } # キャンセルへのリンクがあるか assert_tag 'a', :attributes => { :href => '/main/cancel/10003' } end
実装
class MainController < ApplicationController def index store_location list_param = { :per_page => 10, :order=>'start desc', } case current_user when nil, Counselor list_param[:conditions] = ['status_code = ?', CounselingSession::StatusToStatusCode[:free] ] when Client list_param[:conditions] = ['status_code = ? or (client_id = ? and status_code = ?)', CounselingSession::StatusToStatusCode[:free], current_user.id, CounselingSession::StatusToStatusCode[:reserved] ] end @counseling_session_pages, @counseling_sessions = paginate :counseling_sessions, list_param end ....
ビュー
<h1>カウンセリング予約システム</h1> <br /> <p> <%= "#{current_user.lastname} さん " if current_user %> カウンセリング予約システムへようこそ </p> <ul> <%- case current_user -%> <%- when nil -%> <li><%= link_to 'ログイン', :controller => 'client', :action => 'login' %></li> <li><%= link_to '新規ユーザ登録', :controller => 'client', :action => 'signup' %></li> <%- when Client -%> <li><%= link_to 'ログアウト', :controller => 'client', :action => 'logout' %></li> <li><%= link_to 'ユーザ情報変更', :controller => 'client', :action => 'edit' %></li> <%- when Counselor -%> <li><%= link_to 'ログアウト', :controller => 'client', :action => 'logout' %></li> <li><%= link_to 'ユーザ情報変更', :controller => 'client', :action => 'edit' %></li> <li><%= link_to '管理', :controller => 'reservation', :action => 'index' %></li> <%- end -%> </ul> <p>現在予約可能な時間帯は以下の通りです</p> <hr /> <div class="indent"> <table class="confirm"> <tr> <th>カウンセラー</th> <th><%= human_attribute_name(CounselingSession, 'status') %></th> <th><%= human_attribute_name(CounselingSession, 'start') %></th> <th><%= human_attribute_name(CounselingSession, 'end') %></th> <th><%= human_attribute_name(CounselingSession, 'place') %></th> <th><%= human_attribute_name(CounselingSession, 'memo') %></th> <th><br></th> </tr> <%- for counseling_session in @counseling_sessions -%> <tr> <td><%=h counseling_session.counselor_name %></td> <td><%=h counseling_session.status_j %></td> <td><%=h human_attribute_value(counseling_session, 'start') %></td> <td><%=h human_attribute_value(counseling_session, 'end') %></td> <td><%=h human_attribute_value(counseling_session, 'place') %></td> <td><%=h human_attribute_value(counseling_session, 'memo') %></td> <%- case counseling_session.status -%> <%- when :free -%> <%- case current_user -%> <%- when nil,Client -%> <td><%= link_to '予約', :action => 'reserve', :id => counseling_session %></td> <%- else -%> <td /> <%- end -%> <%- when :reserved -%> <%- if current_user == counseling_session.client -%> <td><%= link_to 'キャンセル', :action => 'cancel', :id => counseling_session %></td> <%- else -%> <td /> <%- end -%> <%- else -%> <td /> <%- end -%> </tr> <%- end -%> </table> <br /> <%= pagination_links @counseling_session_pages %> <br /> </div>
画面イメージ
それで、ここで「予約」のリンクをクリックすると、確認後に予約します。
ここのテスト。
# ログインしないでここに来たらログインさせる def test_reserve_for_guest get :reserve, :id=>10001 assert_redirected_to :controller=>'client', :action => 'login' end # 確認画面の表示 def test_reserve_confirm_for_client get :reserve, { :id=>10001 }, :user=>@cl1 assert_match /free1/, @response.body assert_match /予約しますか/, @response.body end # 予約の実行 def test_reserve_for_client post :reserve, { :id=>10001, :commit=>'予約する' }, :user=>@cl1 assert_match /free1/, @response.body assert_match /予約しました/, @response.body assert assigns(:counseling_session) assert_equal assigns(:counseling_session), CounselingSession.find(10001) assert_equal :reserved, assigns(:counseling_session).status assert_equal @cl1.id, assigns(:counseling_session).client_id assert_equal @cl1, assigns(:counseling_session).client end # 予約済データを予約しようとしてエラー def test_reserve_for_client_error assert_equal @cl1, CounselingSession.find(10003).client post :reserve, { :id=>10003, :commit=>'予約する' }, :user=>@cl2 assert_match /予約できません/, @response.body assert assigns(:counseling_session) assert_equal :reserved, assigns(:counseling_session).status assert_equal @cl1, assigns(:counseling_session).client assert_equal @cl1, CounselingSession.find(10003).client end
実装。これは、テストメソッド一つ作ってはその分だけ実装していきました。
def reserve case current_user when nil, Counselor store_location flash[:notice] = "予約するにはログインが必要です" redirect_to :controller=>'client', :action => 'login' when Client @counseling_session = CounselingSession.find(params[:id]) unless params[:commit] flash[:notice] = "このセッションを予約しますか?" else current_user.reserve(@counseling_session) flash[:notice] = "セッションを予約しました" end end rescue RuntimeError flash[:error] = "このセッションは予約できません(#{$!})" end
ビューは、jascaffoldで作成したパーシャルビューを利用しました。
<h1><%= localize(:model, :counseling_session) %><%= localize(:title, :show) %></h1> <div class="indent"> <%= render :partial=>"models/counseling_sessions/show2" %> <br /> <%= start_form_tag %> <%- case @counseling_session.status -%> <%- when :free -%> <%= submit_tag '予約' %> <%= link_to 'キャンセル', :action => 'index' %> <%- else -%> <%= link_to '一覧へ', :action => 'index' %> <%- end -%> <%= end_form_tag %> </div>
画面イメージ
キャンセルは、予約をコピペして作りました。まずテスト
def test_cancel_for_guest get :cancel, :id=>10001 assert_redirected_to :controller=>'client', :action => 'login' end def test_cancel_confirm_for_client get :cancel, { :id=>10003 }, :user=>@cl1 assert_match /reserved1/, @response.body assert_match /キャンセルしますか/, @response.body end def test_cancel_for_client post :cancel, { :id=>10003, :commit=>'キャンセルする' }, :user=>@cl1 assert_match /reserved1/, @response.body assert_match /キャンセルしました/, @response.body assert assigns(:counseling_session) assert_equal assigns(:counseling_session), CounselingSession.find(10003) assert_equal :free, assigns(:counseling_session).status assert_equal nil, assigns(:counseling_session).client end def test_cancel_for_client_error assert_equal @cl1, CounselingSession.find(10003).client post :cancel, { :id=>10003, :commit=>'キャンセルする' }, :user=>@cl2 assert_match /キャンセルできません/, @response.body assert assigns(:counseling_session) assert_equal :reserved, assigns(:counseling_session).status assert_equal @cl1, assigns(:counseling_session).client assert_equal @cl1, CounselingSession.find(10003).client end
実装。
def cancel case current_user when nil, Counselor store_location flash[:notice] = "予約/キャンセルを行うにはログインが必要です" redirect_to :controller=>'client', :action => 'login' when Client @counseling_session = CounselingSession.find(params[:id]) unless params[:commit] flash[:notice] = "このセッションをキャンセルしますか?" else current_user.cancel(@counseling_session) flash[:notice] = "セッションをキャンセルしました" end end rescue RuntimeError flash[:error] = "このセッションはキャンセルできません(#{$!})" end
ビューと画面イメージは省略します(後程まとめて公開します)。