ナビゲーションバー作成
今回は、ユーザー登録ページ (/users/sign_up) やログインページ (/users/sign_in) へのリンクを置くナビゲーションバーを作成しましょう。
仕様の確認
先に完成形を確認しておきます。
ログインしている時と、ログインしていない時では必要なリンクが異なるので使い分けていきます。
ログインしていない場合
ユーザー登録、ログイン画面へのリンクが表示されます。
ログインしている場合
ログアウトリンクが表示されます。
RSpec でのログイン設定
上記の仕様の通り、今回は「ログインしているかどうか」によって表示されるリンクが変わります。
しかし、テスト内でログインが必要が操作をする前に毎回ログインフォームからログインをするのは面倒です。
これを解決するために、devise のヘルパーメソッドを使えるようにします。
この設定をしておくと sign_in user
という形で 1 行記述するだけで、RSpec テスト内でログインした状態を実現できます。
そのため、spec/rails_helper.rb
の最後の方で Devise::Test::IntegrationHelpers
というモジュールを include しておきます。
spec/rails_helper.rb
...
config.include FactoryBot::Syntax::Methods
config.include Devise::Test::IntegrationHelpers, type: :system # 追加
end
これで System Spec の中で sign_in user
という 1 行で、user
でログインした状態を実現することが出来ます。
※事前に user
には User オブジェクトを代入しておく必要はあります。
このように devise gem には便利なヘルパーメソッドがいくつか用意されているので、知れば知るほど活用の幅が広がります。
テスト追加
どの画面でも共通的に表示するものですので、どの画面の System Spec でチェックしても問題ありませんが、
例えばログイン画面はログインしているとトップページへリダイレクトされてしまうため、チェックには不向きです。
今回は既に作ってあるトップページ (Home#top) の System Spec を修正しましょう。
spec/system/home_spec.rb
require 'rails_helper'
RSpec.describe 'Home', type: :system do
before do
driven_by :selenium_chrome_headless
end
describe 'トップページアクセスの検証' do
it 'Home#top という文字列が表示される' do
visit '/'
expect(page).to have_content('Home#top')
end
end
####### ここから追加 #######
describe 'ナビゲーションバーの検証' do
context 'ログインしていない場合' do
before { visit '/' }
it 'ユーザー登録リンクを表示する' do
expect(page).to have_link('ユーザー登録', href: '/users/sign_up')
end
it 'ログインリンクを表示する' do
expect(page).to have_link('ログイン', href: '/users/sign_in')
end
it 'ログアウトリンクは表示しない' do
expect(page).not_to have_content('ログアウト')
end
end
context 'ログインしている場合' do
before do
user = create(:user) # ログイン用のユーザーを作成
sign_in user # 作成したユーザーでログイン
visit '/'
end
it 'ユーザー登録リンクは表示しない' do
expect(page).not_to have_link('ユーザー登録', href: '/users/sign_up')
end
it 'ログインリンクは表示しない' do
expect(page).not_to have_link('ログイン', href: '/users/sign_in')
end
it 'ログアウトリンクを表示する' do
expect(page).to have_content('ログアウト')
end
it 'ログアウトリンクが機能する' do
click_button 'ログアウト'
# ログインしていない状態のリンク表示パターンになることを確認
expect(page).to have_link('ユーザー登録', href: '/users/sign_up')
expect(page).to have_link('ログイン', href: '/users/sign_in')
expect(page).not_to have_content('ログアウト')
end
end
end
end
この時点では当然、テストがコケることを確認します。
ただし、一部リンクが「表示されないこと」を確認しているテストもあるため、一部のテストはコケないことに注意してください。
$ bin/rspec spec/system/home_spec.rb
...
Finished in 11.44 seconds (files took 0.45402 seconds to load)
8 examples, 4 failures
Failed examples:
rspec ./spec/system/home_spec.rb:20 # Home ナビゲーションバーの検証 ログインしていない場合 ユーザー登録リンクを表示する
rspec ./spec/system/home_spec.rb:24 # Home ナビゲーションバーの検証 ログインしていない場合 ログインリンクを表示する
rspec ./spec/system/home_spec.rb:48 # Home ナビゲーションバーの検証 ログインしている場合 ログアウトリンクを表示する
rspec ./spec/system/home_spec.rb:52 # Home ナビゲーションバーの検証 ログインしている場合 ログアウトリンクが機能する
実装
では、上記のテストが通るように設定していきましょう。
部分テンプレート作成
app/views/shared
ディレクトリに _navbar.html.erb
というファイルを作成します。
<nav class="bg-gray-800 border-gray-200 px-2 sm:px-4 py-2.5">
<div class="container flex flex-wrap justify-between items-center mx-auto">
<%= link_to "TechLog", "/", class: "self-center text-white text-xl font-semibold whitespace-nowrap" %>
<div class="w-full md:block md:w-auto">
<ul class="flex flex-col mt-4 md:flex-row md:space-x-8 md:mt-0 md:text-sm md:font-medium">
<% if current_user %>
<li>
<%= button_to "ログアウト", destroy_user_session_path, class: "block py-2 pr-4 pl-3 text-gray-400 hover:text-white border-b border-gray-700 hover:bg-gray-700 md:hover:bg-transparent md:border-0 md:hover:text-blue-white md:p-0", method: :delete %>
</li>
<% else %>
<li>
<%= link_to "ユーザー登録", new_user_registration_path, class: "block py-2 pr-4 pl-3 text-gray-400 hover:text-white border-b border-gray-700 hover:bg-gray-700 md:hover:bg-transparent md:border-0 md:hover:text-blue-white md:p-0" %>
</li>
<li>
<%= link_to "ログイン", new_user_session_path, class: "block py-2 pr-4 pl-3 text-gray-400 hover:text-white border-b border-gray-700 hover:bg-gray-700 md:hover:bg-transparent md:border-0 md:hover:text-blue-white md:p-0" %>
</li>
<% end %>
</ul>
</div>
</div>
</nav>
ちなみに、ログアウトリンクだけは link_to
ではなく button_to
となっていることに注意してください。
これは、デフォルトでは link_to
に method: :delete
をただ追加しても DELET メソッドを実現できないためです。
さらに、フラッシュメッセージの部分テンプレートを読み込んだ時と同じく
今回作成した部分テンプレートを app/views/layouts/application.html.erb
に追記します。
app/views/layouts/application.html.erb
...
<body class="h-screen bg-blue-50">
<%= render 'shared/flash' %>
<%= render 'shared/navbar' %> <%# 追記 %>
<main class="container mx-auto mt-20 py-8 px-5 flex items-center justify-center">
<%= yield %>
</main>
</body>
</html>
テスト実行
実装が完了しましたので、テストがすべて成功することを確認します。
$ bin/rspec spec/system/home_spec.rb
...
ナビゲーションバーの検証
ログインしていない場合
ユーザー登録リンクを表示する
ログインリンクを表示する
ログアウトリンクは表示しない
ログインしている場合
ユーザー登録リンクは表示しない
ログインリンクは表示しない
ログアウトリンクを表示する
ログアウトリンクが機能する
Finished in 3.45 seconds (files took 0.41146 seconds to load)
8 examples, 0 failures
動作確認
すべてのテストに通りましたが、見た目としても問題ないことを確認します。
bin/dev
コマンドで開発用サーバを起動してから、各リンクを確認していきます。
ログインしていない場合
最初はログアウトした状態で、ユーザー登録リンクとログインリンクが表示されることを確認します。
<img width="235" alt="image" src="https://user-images.githubusercontent.com/68495563/180642033-97ef6b2a-d904-4d9a-ab8f-e44bdeeb2dac.png">
また、それぞれのリンクをクリックし、各ページへ遷移できることも確認しておくといいでしょう。
ログインしている場合
今度はログインした時のナビゲーションバーを確認します。
ログアウトリンクが表示されていれば OK です。
<img width="145" alt="image" src="https://user-images.githubusercontent.com/68495563/180642109-f0f5ecb2-6e74-4330-abc7-58bb218cc6ff.png">
ログアウトリンクをクリックするとログアウトされ、ユーザー登録とログインリンクも表示されるようになることを確認しておきます。
<img width="235" alt="image" src="https://user-images.githubusercontent.com/68495563/180642033-97ef6b2a-d904-4d9a-ab8f-e44bdeeb2dac.png">
変更をコミット
これでナビゲーションバーを実装は完了です。
変更をコミットしておきます。
$ git add .
$ git commit -m "ナビゲーションバーを追加"
$ git push
宿題
have_link マッチャー
今回、Capybara でユーザー登録・ログインのテキストリンクを探すために have_link
というマッチャを使いました。
have_link
マッチャがどういう要素を見つけてくるのかは、前にも紹介した人気の Qiita 記事で復習しておきましょう。
deviseのRSpec用ヘルパー
RSpec の中でログイン状態を実現するためのヘルパーを使いましたね。
もう少し簡単なアプリケーションで導入する時の流れを全体像で掴んでおいた方が理解が進むので、こちらの記事で流れを改めて把握しておきましょう。