💡
この記事は Middleman 時代に書いた古いものです。記録のため、astro-notion-blog に移行していますが、あまり参考にしないでください。
request spec による edit のテストと実装
-
GET #edit の spec を spec/requests/kurasus_spec.rb に記載する. edit では :id で指定された一つのクラスを取得する. 何も対処しないと,URL の :id を偽装することで,他人のクラスを編集できてしまうことになる. そこで,自分の所有しているクラスの場合と,所有していないクラスの場合でテストを二つ用意する.
# テストの最初に追加する.自分が所有しないクラスを let で遅延取得できるようにしておく. let(:not_mine) { kurasu_factory :taro3300 } (中略) describe 'GET #edit' do context 'owned object' do subject { -> { get edit_kurasu_path(object) } } it_behaves_like :response_status_check, 200 it_behaves_like :response_body_includes, '2300' end context 'not owned object' do subject { -> { get edit_kurasu_path(not_mine) } } it_behaves_like :response_status_check, 302 it_behaves_like :redirect_to it_behaves_like :flash_alert_message, 'クラスを編集する権限がありません.' end end
-
GET #edit の実装を app/controllers/kurasus_controller.rb に記載する. 今後,update, destroy, show などでも利用するので,get_one というクラスを一つ取得するプライベートメソッドを用意しておく. このため,edit, update, destroy, show の時だけ,get_one を before_action するように設定している. この get_one メソッドでは,current_teacher.kurasus でフィルタされているため,他人のクラスのものは取得できず nil が返ってくるはずである. そこで,edit では @kurasu が nil の時に redirect_to で kurasus_path に飛ばしている. この時,edit の render を描画して欲しくないため,and return を追加している(redirect_to が true を返すので,自動的に and の後ろの return が実行される).
# 先頭に追加 before_action :get_one, only: %i[edit update destroy show] (中略) def edit redirect_to(kurasus_path(edit_mode: true), alert: alert_message(Kurasu)) and return if @kurasu.nil? end (中略) def get_one @kurasu = current_teacher.kurasus.find_by_id(params[:id]) end private :get_one
-
GET #edit のビューを app/views/kurasus/edit.html.haml に記載する. locale で差異を 吸収しているため,new.html.haml と edit.html.haml は同一内容である.そのためコピー(またはハードリンク)すればよい.
cp app/views/kurasus/{new,edit}.html.haml
request spec による update のテストと実装
-
PATCH #update の spec を spec/requests/kurasus_spec.rb に記載する. 更新に成功する場合,失敗する場合,他人のクラスを取得した場合の三種類を確認できればよい. 利用した shared_example は以下の通りである(追加分).
- change_object_value_by_update: モデルの属性が変化したか確認
- not_change_object_value_by_update: モデルが属性が変化していないことを確認
describe 'PATCH #update' do before { @attrs = object.attributes } context 'owned object' do subject { -> { patch kurasu_path(object), params: {kurasu: @attrs} } } context '正しいパラメータに対して' do before { @attrs['name'] = 'new name' } it_behaves_like :response_status_check, 302 it_behaves_like :change_object_value_by_update, Kurasu, :name, 'new name' it_behaves_like :redirect_to it_behaves_like :flash_notice_message, 'クラスを更新しました.' end context '不正なパラメータに対して' do before { @attrs['name'] = nil } it_behaves_like :response_status_check, 200 it_behaves_like :not_change_object_value_by_update, Kurasu, :name it_behaves_like :flash_alert_message, 'クラスが更新できません.' end end context 'not owned object' do subject { -> { put kurasu_path(not_mine), params: {kurasu: @attrs} } } it_behaves_like :response_status_check, 302 it_behaves_like :redirect_to it_behaves_like :flash_alert_message, 'クラスが更新できません.' end end
-
PATCH #update の実装を app/controllers/kurasus_controller.rb に記載する.
def update redirect_to(kurasus_path, alert: alert_message(Kurasu)) and return if @kurasu.nil? if @kurasu.update_attributes(kurasu_params) redirect_to kurasus_path(edit_mode: true), notice: notice_message(Kurasu) else flash.now[:alert] = alert_message(Kurasu) render action: :edit end end
-
最終的な guard 出力はこんな感じになった(本日分のみ).全てテストが通過している.
GET #edit owned object behaves like response_status_check response should be 200 behaves like response_body_includes response body includes 2300 not owned object behaves like response_status_check response should be 302 behaves like redirect_to should redirect to "/kurasus" behaves like flash_alert_message should eq "クラスを編集する権限がありません." PATCH #update owned object 正しいパラメータに対して behaves like response_status_check response should be 302 behaves like change_object_value_by_update should change `klass.find(object.id).send(key)` from "2300" to "new name" behaves like redirect_to should redirect to "/kurasus?edit_mode=true" behaves like flash_notice_message should eq "クラスを更新しました." 不正なパラメータに対して behaves like response_status_check response should be 200 behaves like not_change_object_value_by_update should not change `klass.find(object.id).send(key)` behaves like flash_alert_message should eq "クラスが更新できません." not owned object behaves like response_status_check response should be 302 behaves like redirect_to should redirect to "/kurasus?edit_mode=true" behaves like flash_alert_message should eq "クラスが更新できません."
長くなったので今日はここまで