自分と同じように、Rails 5.1 第4版 11.3.3 演習3でつまずいた人のお役に立てるといいなと思いまとめました。
答えをまとめているサイトを3つくらい見たのですが、演習3だけは、答えを書いていないか、回答どおりにすると、別の箇所でエラーが起きます。(自分が探しきれていないだけかもしれません)
なので、自分でエラーを修正しました。
演習1は影響ないので飛ばします。
演習2
現在は、/usersのユーザーindexページを開くとすべてのユーザーが表示され、/users/:idのようにIDを指定すると個別のユーザーを表示できます。しかし考えてみれば、有効でないユーザーは表示する意味がありません。そこで、リスト 11.40のテンプレートを使って、この動作を変更してみましょう9。なお、ここで使っているActive Recordのwhereメソッドについては、13.3.3でもう少し詳しく説明します。
これに対して、リスト11.40はこのようになっています。
リスト 11.40: 有効なユーザーだけを表示するコードのテンプレート
app/controllers/users_controller.rb
class UsersController < ApplicationController
.
.
.
def index
@users = User.where(activated: FILL_IN).paginate(page: params[:page])
end
def show
@user = User.find(params[:id])
redirect_to root_url and return unless FILL_IN
end
.
.
.
end
この演習は、indexアクションにwhereメソッドを追加したことにより、activated: trueのユーザーが表示されるようになります。
また、showアクションについてはactivated?メソッドによって、アクティベート済みのユーザでなければ、root_urlにリダイレクトします。
なので、FILL_INの箇所が、以下のようになります。
class UsersController < ApplicationController
before_action :logged_in_user, only: [:index, :edit, :update, :destroy]
before_action :correct_user, only: [:edit, :update]
before_action :admin_user, only: :destroy
def index
@users = User.where(activated: true).paginate(page: params[:page])
end
def show
@user = User.find(params[:id])
redirect_to root_url and return unless @user.activated?
end
この変更をしたことにより、アクティベートされていないユーザーは、indexページにひょうじされなくなりました。
次は演習3です
ここまでの演習課題で変更したコードをテストするために、/users と /users/:id の両方に対する統合テストを作成してみましょう。
とあるので演習2に対するテストを作成します。
有効化されていないユーザーを作成しないことには、indexアクション、showアクションで表示されていないかを調べられないので、fixtures/users.ymlのユーザーをひとり、有効化されていないことにします。
fixtures/users.yml
.
.
.
lana:
name: Lana Kane
email: hands@example.gov
password_digest: <%= User.digest('password') %>
activated: false
activated_at: <%= Time.zone.now %>
activated: falseにしました。
このユーザーをsetupメソッドに追加します。
require 'test_helper'
class UsersIndexTest < ActionDispatch::IntegrationTest
def setup
@admin = users(:michael)
@non_admin = users(:archer)
@non_activated = users(:lana)
end
あとは、テストを追加します。
app/controllers/users_controller.rb
test "not allow the not activated user" do
#アクティベートされていないユーザーを許可しない
log_in_as(@non_activated)
#アクティベートしていないユーザーでログイン
assert_not @non_activated.activated?
#アクティベートされていなければ、GREEN
get users_path
#getリクエストを送る(ユーザー一覧ページ)
assert_select "a[href=?]", user_path(@non_activated), count: 0
#ユーザー一覧ページのなかに、アクティベートされていないユーザのリンクがなければGREEN
get user_path(@non_activated)
#getリクエストを送る(アクティベートされていないユーザーのprofileページを表示)
assert_redirected_to root_url
#root_urlへリダイレクトしたらテストはGREEN
end
これで、このテスト(test "not allow the not activated user" do end)はGREENなのですが、
test/integration/users_index_test.rb
test "index as admin including pagination and delete links" do
log_in_as(@admin)
get users_path
assert_template 'users/index'
assert_select 'div.pagination'
first_page_of_users = User.paginate(page: 1)
first_page_of_users.each do |user|
assert_select 'a[href=?]', user_path(user), text: user.name
unless user == @admin
assert_select 'a[href=?]', user_path(user), text: 'delete'
end
end
assert_difference 'User.count', -1 do
delete user_path(@non_admin)
end
end
もとからあった、このテストがREDになります。
テストの結果このあたりの行でエラーがあると表示されたので、テストないようの、この部分を見ていきます。
first_page_of_users = User.paginate(page: 1)
first_page_of_users.each do |user|
assert_select 'a[href=?]', user_path(user), text: user.name
unless user == @admin
assert_select 'a[href=?]', user_path(user), text: 'delete'
end
end
first_page_of_user.each do |user|
でuser変数には、1ページ目のユーザーが代入されます。
そのユーザーの数だけ、
assert_select 'a[href=?]', user_path(user), text: user.name
でuser_pathをチェックするのですが、演習2をおこなったことにより、アクティベートされたユーザーが(activated: true)表示されています。なので、アクティベートされていないユーザーは表示されていません。
演習2の下記の箇所です。
def index
@users = User.where(activated: true).paginate(page: params[:page])
end
なので、アクティベートされていないユーザーのuser_pathがユーザー一覧のページに(users_path)表示されていないので、REDになります。
これを解決するために、アクティベートされていないユーザーは、このテストを回避することにします。それはそれで問題がおこりそうですが、
すでに、演習3で追加したテスト
test "not allow the not activated user"
の中で
assert_select "a[href=?]", user_path(@non_activated), count: 0
このように、アクティベートされていないユーザーのリンク(user_path)は表示されていない(count: 0)ことがわかっているので大丈夫だと判断します。
ということで、テスト内容を変更します。
first_page_of_users = User.paginate(page: 1)
first_page_of_users.each do |user|
unless user == @non_activated
assert_select 'a[href=?]', user_path(user), text: user.name
end
unless user == @admin
assert_select 'a[href=?]', user_path(user), text: 'delete'
end
end
追加した内容は、以下です。
unless == @non_activated
end
この内容を追加したことによりアクティベートされていないユーザーは、
assert_select 'a[href=?]', user_path(user), text: user.name
このテストを回避しました。
これでも、まだえらーがでるので、次は
unless user == @admin
assert_select 'a[href=?]', user_path(user), text: 'delete'
end
この部分です。この時点で
admin属性がtrueのユーザーは、ユーザーを削除するリンクが表示されません。また、削除用のリンクである、deleteというテキストも表示されません。
なので、admin属性がtrueのユーザーは
assert_select 'a[href=?]', user_path(user), text: 'delete'
このテストを通過しないようにしています。
これと同様に、アクティベートされていないユーザーも削除用のリンクが表示されませんし、deleteというテキストも表示されません。(そもそも、アクティベートされていないユーザーは、ユーザー一覧に表示されていません)
なので、アクティベートされていないユーザーもこのテストを通過しないようにします。
unless user == @admin || @non_activated
assert_select 'a[href=?]', user_path(user), text: 'delete'
end
このように、|| @non_activatedとすることにより、
@adminか、@non_activatedはこのテストを通過しないことになりました。
ここでテストはGREENになります。
ためしに、演習2の内容を元にもどして、テストがREDになることを確認しました。
Expected response to be a <3XX: redirect>, but was a <200: OK>
テスト結果はリダイレクトのレスポンスがくるはずが、リダイレクトでなく、成功を示しているのでテストはREDです。
もう一度演習2の内容を直して。テストをすると、テストはGREENになります。
この演習内容だけは、自分で探した範囲では、詳細が書いていなかったので、まとめてみました。