質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Ruby on Rails 5

Ruby on Rails 5は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Q&A

解決済

3回答

1180閲覧

子オブジェクト作成時、親オブジェクトを更新するテストについて

satoshitodaka

総合スコア7

Ruby on Rails 5

Ruby on Rails 5は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

0グッド

0クリップ

投稿2021/06/09 03:33

前提・実現したいこと

経費申請アプリを作成しています。
初めての質問となりますので、語句の誤り・情報の不足があればご指摘ください。

子のオブジェクトを新規作成した場合に
作成内容に応じて親オブジェクトのカラムを編集したいです。
テスト環境で操作した場合は意図通りに動作しますが、テストにパスしないため
テスト内容に不備がないかご指摘いただけないでしょうか。

発生している問題・エラーメッセージ

 adminが申請を承認する際、申請オブジェクトとユーザーに紐づく承認オブジェクトを作成します。

承認コントローラのcreateアクションにて、以下の処理を行っています。
①承認オブジェクトを作成する。
newページの承認リンク(承認or否認)にそれぞれパラメータを持たせており、この値に応じて
承認オブジェクトの承認ステータスをtrueまたはfalseと設定します。
②申請オブジェクトを呼び出し、承認オブジェクトの承認ステータスに応じて
親オブジェクトの承認ステータスに反映させる(一致させる)。

上記の内容を統合テストに記述しましたが
テスト内では②の処理が行われていないようで、以下の通り失敗します。

原因が分かる方いらっしゃいましたら、よろしくお願いいたします。

$ rails t Started with run options --seed 4862 FAIL ApproverActionTest#test_admin_user_can_approve_other_statement (1.84s) Expected: true Actual: false test/integration/approver_action_test.rb:26:in `block in <class:ApproverActionTest>' #なお、テスト実行後の各オブジェクトは以下のようになっています。 #申請オブジェクト(親) <TripStatement id: 777684020, distination: "kyoto", purpose: "recruit", start_at: "2021-04-15 08:34:55", finish_at: "2021-04-15 21:34:55", work_done_at: "2021-04-15 18:34:55", applied: true, applied_at: "2021-04-20 08:34:55", approved: false, approved_at: nil, user_id: 1038133505, created_at: "2021-06-08 23:45:42", updated_at: "2021-06-08 23:45:42"> #承認オブジェクト(子) <Approval id: 980191026, trip_statement_id: 777684020, approval: true, comment: nil, created_at: "2021-06-08 23:45:44", updated_at: "2021-06-08 23:45:44", user_id: 617136053>

###app/views/approval/new.html.erb

<% provide(:title, "承認画面") %> <h1>承認画面</h1> <h3>出張情報</h3> <%# 情報の表示のみなので割愛 %> <% if @trip_statement.user_id != current_user.id %> <h3>承認</h3> <%= link_to "承認する", trip_statement_approval_index_path(@trip_statement.id, approval: "false"), method: :post, class:"btn btn-primary btn-block btn-block" %> <%= link_to "否認する", trip_statement_approval_index_path(@trip_statement.id, :approval => "false"), method: :post, class:"btn btn-primary btn-block btn-block" %> <% end %>

###app/controllers/approval_controller.rb

class ApprovalController < ApplicationController before_action :authenticate_user! before_action :admin_user? before_action :same_company?, only: [:new, :create, :edit, :update] before_action :approve?, only: [:new, :create] before_action :applied?, only: [:new, :create, :edit, :update] # newとcreateと関連するメソッドを抜粋してます。 def new @trip_statement = TripStatement.find(params[:trip_statement_id]) @user = current_user @approval = @user.approval.build(trip_statement_id: @trip_statement.id) @expences = @trip_statement.expences.all #承認画面にて、紐づく旅費全てを表示する。 end def create @trip_statement = TripStatement.find(params[:trip_statement_id]) if params[:approval] == "true" @approval = current_user.approval.create(trip_statement_id: @trip_statement.id, approval: true) @approval.trip_statement.update(approved: true, approved_at: Time.zone.now) elsif params[:approval] == "false" @approval = current_user.approval.create(trip_statement_id: @trip_statement.id, approval: false) @trip_statement.update(approved: false, approved_at: Time.zone.now) else redirect_to trip_statement_approval_index_path flash[:warning] = "問題が発生しました。再度お試しください。" end @trip_statement.save # @approval.save if params[:approval] == "true" flash[:success] = "承認しました!" elsif params[:approval] == "false" flash[:warning] = "否認しました。" end redirect_to trip_statement_approval_index_url end private def admin_user? redirect_to root_url unless current_user.admin end def approve? @trip_statement = TripStatement.find(params[:trip_statement_id]) if @trip_statement.approved redirect_to trip_statement_approval_index_url flash[:danger] = "承認済の申請です。" end end def applied? @trip_statement = TripStatement.find(params[:trip_statement_id]) if @trip_statement.applied == false redirect_to trip_statement_approval_index_url flash[:danger] = "未提出の申請です。" end end def same_company? @trip_statement = TripStatement.find(params[:trip_statement_id]) if @trip_statement.user.company_id != current_user.company_id redirect_to trip_statement_approval_index_url flash[:danger] = "他社の申請は操作できません" end end end

test/integration/approver_action_test.rb

def setup @user = users(:my_normal) @approver = users(:my_admin) end test "admin_user can approve other statement" do login_as(@approver) @other_users_statement = trip_statements(:my_applied_statement) get approval_index_path assert_template 'approval/index' get new_trip_statement_approval_path(@other_users_statement) assert_template 'approval/new' assert_difference 'Approval.count', 1 do post trip_statement_approval_index_path(@other_users_statement), params: { approval: "true" } @approval = Approval.last end assert_equal true, @approval.approval assert_equal @user.id, @other_users_statement.user_id assert_equal true, @other_users_statement.approved #=> falseになる end

###test/fixtures/trip_statements.yml

my_applied_statement: distination: kyoto purpose: recruit start_at: 2021-04-15 08:34:55 finish_at: 2021-04-15 21:34:55 work_done_at: 2021-04-15 18:34:55 applied: true applied_at: 2021-04-20 08:34:55 approved: false user: my_normal

###test/fixtures/users.yml

my_admin: company: MY # department_id: name: my_admin email: my_admin@my.com birthday: 1995-06-17 admin: true system_admin: false encrypted_password: <%= Devise::Encryptor.digest(User, 'password') %> my_normal: company: MY # department_id: name: my_normal email: my_normal@my.com birthday: 1997-07-25 admin: false system_admin: false encrypted_password: <%= Devise::Encryptor.digest(User, 'password') %>

補足情報(FW/ツールのバージョンなど)

・Ruby: 2.6.6
・rails: 5.2.5

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

post trip_statement_approval_index_path が奇妙なのですが。。。
index ですか?
rails

投稿2021/06/14 14:58

winterboum

総合スコア23567

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

satoshitodaka

2021/07/04 11:00

winterboumさん、コメントいただきありがとうございます。 また、ご返信が遅くなり申し訳ありませんでした。 ご指摘いただいたパスの不自然さについてですが ルーティングで、resourcesでリソースの単数形を指定したことが原因でした。 approvalは複数形がない単語のようで、何も考えずに単数形のapprovalを指定していたのですが これによりパスの末尾がindex_pathになっていたようです。 最終的には、パスのパラメータでアクション内の処理を分岐することをやめました。 アクション自体を分けて動作をシンプルにすることで、機能・テスト共に正しく動作するようになりました。 質問に記載の内容では実装しないことになりましたが winterboumさんのコメントが解決のヒントになりましたので、本当にありがとうございました。
guest

0

本件、RSpecに移行中のため個人的には意義が薄れているのですが
メンターへのご相談で解決しましたので以下共有させてください。

以下の通り、reloadを追加することで期待通りテストが通るようになりました。
assert_equal true, @other_users_statement.reload.approved(以下テストで下から2行目)
reloadをつけない場合、最初に設定した変数をそのまま呼び出してしまうため、テストが通らなかったようです。
ご参考になれば幸いです。

test "admin_user can approve other statement" do login_as(@approver) @other_users_statement = trip_statements(:my_applied_statement) get approval_index_path assert_template 'approval/index' get new_trip_statement_approval_path(@other_users_statement) assert_template 'approval/new' assert_difference 'Approval.count', 1 do post trip_statement_approval_index_path(@other_users_statement), params: { approval: "true" } @approval = Approval.last end assert_equal true, @approval.reload.approval assert_equal @user.id, @other_users_statement.user_id assert_equal true, @other_users_statement.approved end

投稿2021/08/10 15:08

編集2021/08/10 23:44
satoshitodaka

総合スコア7

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

コメントに記載の通り、リンクのパラメータで処理を分岐することをやめました。
申請を否認するアクションを新たに作成することで実装、テストがパスするようになりました。
よろしければご確認ください。

route.rb(抜粋)

Rails.application.routes.draw do resources :trip_statements, shallow: true do patch 'submit', on: :member resources :expences resources :approvals, only: [:index, :new, :create, :edit, :update, :destroy] do collection do get 'approved' get :denied end end end post 'trip_statements/:trip_statement_id/deny' => 'approvals#deny', as: :deny_approval end

approval_controller.rb(抜粋)

def new @trip_statement = TripStatement.find(params[:trip_statement_id]) @user = current_user @approval = @user.approvals.build(trip_statement_id: @trip_statement.id) @expences = @trip_statement.expences.all #承認画面にて、紐づく旅費全てを表示する。 end def create @trip_statement = TripStatement.find(params[:trip_statement_id]) @approval = current_user.approvals.create(trip_statement_id: @trip_statement.id, approval: true) @trip_statement.update(approved: true, approved_at: Time.zone.now) redirect_to approvals_index_url flash[:success] = "承認しました!" end def deny @trip_statement = TripStatement.find(params[:trip_statement_id]) @approval = current_user.approvals.build(deny_params) @approval.update(trip_statement_id: @trip_statement.id, approval: false) @trip_statement.update(approved: false, approved_at: Time.zone.now, applied: false) redirect_to approvals_index_url flash[:warning] = "否認しました。" end

new.html.erb(承認と否認のフォーム)

<% if current_user.admin && @trip_statement.user_id != current_user.id %> <h3>承認</h3> <%= link_to "承認する", trip_statement_approvals_path(@trip_statement.id, approval: "true"), method: :post, class:"btn btn-primary btn-block btn-block" %> <%= form_with(model: [@trip_statement, @approval], url:deny_approval_path(@trip_statement.id), local: true) do |f| %> <%= f.label :comment, "コメント" %> <%= f.text_area :comment %> <%= f.submit "否認する", class: "btn btn-primary" %> <% end %> <% end %>

否認のテスト

# ユーザーの出張申請を承認する。 test "admin_user can approve other statement" do login_as(@approver) @other_users_statement = trip_statements(:my_applied_statement) get approvals_index_path assert_template 'approvals/index' get new_trip_statement_approval_path(@other_users_statement) assert_template 'approvals/new' assert_difference 'Approval.count', 1 do post trip_statement_approvals_path(@other_users_statement)#, params: { approval: "true" } end @approval = Approval.last assert_equal true, @approval.approval assert_equal @user.id, @other_users_statement.user_id # assert_equal true, @other_users_statement#.approved assert_equal @other_users_statement.id, @approval.trip_statement_id end # ユーザーの出張承認を否認する。 test "admin_user can deny other statement" do login_as(@approver) @other_users_statement = trip_statements(:my_applied_statement) get approvals_index_path assert_template 'approvals/index' get new_trip_statement_approval_path(@other_users_statement) assert_template 'approvals/new' assert_difference 'Approval.count', 1 do post deny_approval_path(@other_users_statement, comment: "test comment") end @approval = Approval.last assert_equal false, @approval.approval assert_equal "test comment", @approval.comment assert_equal false, @other_users_statement.approved end

投稿2021/07/04 11:15

satoshitodaka

総合スコア7

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問