Home#top の削除
さて、現在は '/'
にアクセスすると HomeController の #top アクションが呼ばれ、仮のトップページが表示されていました。
しかし TechLog ではトップページに学習ログ一覧を表示したいため、HomeController 関連をすべて消していきます。
ただし、ナビゲーションバーのテストは HomeController#top で検証していたため、そのあたりを投稿機能のテストに移行することに注意してください。
今回は HomeController に関し、以下の変更を行います。
- テストの変更
- Request Spec
- posts のルーティング
- home の Request Spec 削除
- System Spec
- ナビゲーションバーのテストを posts へ移行
- posts#index のルーティング
- home の System Spec 削除
- Request Spec
- ルーティングの変更
- HomeController の削除
- View の削除
テストの変更
今回は大きな変更であり、かつやることが明確であるためテストから先に変更してみましょう。
Request Spec
まずは Request Spec の変更を行います。
posts#index のルーティング
現在、posts#index へのパスは /posts
でした。
それがこれからはトップページのパス、つまり /
となるのでテストを変更しておきます。
変更前: spec/requests/posts_spec.rb
describe 'GET /posts' do
context 'ログインしていない場合' do
it 'HTTPステータス200を返す' do
get '/posts'
expect(response).to have_http_status '200'
end
end
context 'ログインしている場合' do
it 'HTTPステータス200を返す' do
sign_in @user
get '/posts'
expect(response).to have_http_status '200'
end
end
end
変更後: spec/requests/posts_spec.rb
describe 'GET /' do # 修正
context 'ログインしていない場合' do
it 'HTTPステータス200を返す' do
get '/' # 修正
expect(response).to have_http_status '200'
end
end
context 'ログインしている場合' do
it 'HTTPステータス200を返す' do
sign_in @user
get '/' # 修正
expect(response).to have_http_status '200'
end
end
end
System Spec
次は System Spec に変更を行います。
ナビゲーションバーのテスト移行
home の System Spec には、ナビゲーションバーに関する以下のテストが含まれていました。
<details>
<summary>spec/system/home_spec.rb</summary>
...
describe 'ナビゲーションバーの検証' do
context 'ログインしていない場合' do
before { visit '/' }
it 'ログ一覧リンクを表示する' do
expect(page).to have_link('ログ一覧', href: '/posts')
end
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_link('ログ投稿', href: '/posts/new')
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).to have_link('ログ一覧', href: '/posts')
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_link('ログ投稿', href: '/posts/new')
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_button('ログアウト')
end
end
end
end
</details>
ログイン状態に応じたナビゲーションバーの表示のテストを home の System Spec にまとめて書いていましたが、
中身は「ユーザー機能」と「ログ投稿機能」に関するテストが混在していました。
この機会に、それぞれ users の System Spec と posts の System Spec に移行しましょう。
home の System Spec をそれぞれの System Spec にコピペで貼り付け、それぞれの機能に関する箇所だけを残すようにすると移行が楽です。
spec/system/posts_spec.rb
...
#### ここから追加 ####
describe 'ナビゲーションバーの検証' do
context 'ログインしていない場合' do
before { visit '/' }
it 'ログ一覧リンクを表示する' do
expect(page).to have_link('ログ一覧', href: '/posts')
end
it 'ログ投稿リンクを表示しない' do
expect(page).not_to have_link('ログ投稿', href: '/posts/new')
end
end
context 'ログインしている場合' do
before do
user = create(:user) # ログイン用のユーザーを作成
sign_in user # 作成したユーザーでログイン
visit '/'
end
it 'ログ一覧リンクを表示する' do
expect(page).to have_link('ログ一覧', href: '/posts')
end
it 'ログ投稿リンクを表示する' do
expect(page).to have_link('ログ投稿', href: '/posts/new')
end
end
end
#### ここまで追加 ####
spec/system/users_spec.rb
...
#### ここから追加 ####
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_button('ログアウト')
end
end
end
#### ここまで追加 ####
posts#index のルーティング
Post の System Spec についてですが、投稿一覧のパスは /posts
ではなく /
になったので修正しておきましょう。
spec/system/posts_spec.rb
require 'rails_helper'
describe 'Post', type: :system do
...
describe 'ログ投稿機能の検証' do
...
context 'ログインしている場合' do
...
context 'パラメータが正常な場合' do
it 'Postを作成できる' do
expect { subject }.to change(Post, :count).by(1)
expect(current_path).to eq('/') # 修正
...
describe 'ログ一覧機能の検証' do
before { visit '/' } # 修正
...
describe 'ログ削除機能の検証' do
context '投稿したユーザーでログインしている場合' do
...
it '削除ボタンをクリックすると削除できる' do
...
# リダイレクト後の画面確認
expect(current_path).to eq('/') # 修正
...
describe 'ナビゲーションバーの検証' do
context 'ログインしていない場合' do
before { visit '/' }
it 'ログ一覧リンクを表示する' do
expect(page).to have_link('ログ一覧', href: '/') # 修正
end
...
context 'ログインしている場合' do
...
it 'ログ一覧リンクを表示する' do
expect(page).to have_link('ログ一覧', href: '/posts') # 修正
...
修正後の Post System Spec の全文は以下のようになります。
<details>
<summary>spec/system/posts_spec.rb</summary>
require 'rails_helper'
describe 'Post', type: :system do
before do
driven_by :selenium_chrome_headless # ヘッドレスモードで実行
@user = create(:user) # ログイン用ユーザー作成
@post = create(:post, title: 'RSpec学習完了', content: 'System Specを作成した', user_id: @user.id)
@post2 = create(:post, title: 'RSpec学習完了 2', content: 'System Specを作成した 2', user_id: @user.id)
end
# 投稿フォーム
let(:title) { 'テストタイトル' }
let(:content) { 'テスト本文' }
describe 'ログ投稿機能の検証' do
# ログ投稿を行う一連の操作を subject にまとめる
subject do
fill_in 'post_title', with: title
fill_in 'post_content', with: content
click_button 'ログを記録'
end
context 'ログインしていない場合' do
before { visit '/posts/new' }
it 'ログインページへリダイレクトする' do
expect(current_path).to eq('/users/sign_in')
expect(page).to have_content('ログインしてください。')
end
end
context 'ログインしている場合' do
before do
sign_in @user
visit '/posts/new'
end
it 'ログインページへリダイレクトしない' do
expect(current_path).not_to eq('/users/sign_in')
end
context 'パラメータが正常な場合' do
it 'Postを作成できる' do
expect { subject }.to change(Post, :count).by(1)
expect(current_path).to eq('/')
expect(page).to have_content('投稿しました')
end
end
context 'パラメータが異常な場合' do
let(:title) { nil }
it 'Postを作成できない' do
expect { subject }.not_to change(Post, :count)
expect(page).to have_content('投稿に失敗しました')
end
it '入力していた内容は維持される' do
subject
expect(page).to have_field('post_content', with: content)
end
end
end
end
describe 'ログ詳細機能の検証' do
before { visit "/posts/#{@post.id}" }
it 'Postの詳細が表示される' do
expect(page).to have_content('RSpec学習完了')
expect(page).to have_content('System Specを作成した')
expect(page).to have_content(@user.nickname)
end
end
describe 'ログ一覧機能の検証' do
before { visit '/posts' }
it '1件目のPostの詳細が表示される' do
expect(page).to have_content('RSpec学習完了')
expect(page).to have_content('System Specを作成した')
expect(page).to have_content(@user.nickname)
end
it '2件目のPostの詳細が表示される' do
expect(page).to have_content('RSpec学習完了 2')
expect(page).to have_content('System Specを作成した 2')
expect(page).to have_content(@user.nickname)
end
it '投稿タイトルをクリックすると詳細ページへ遷移する' do
click_link 'RSpec学習完了'
expect(current_path).to eq("/posts/#{@post.id}")
end
end
describe 'ログ削除機能の検証' do
context '投稿したユーザーでログインしている場合' do
before do
sign_in @user
visit "/posts/#{@post.id}"
end
it '削除ボタンを表示する' do
expect(page).to have_button('削除')
end
it '削除ボタンをクリックすると削除できる' do
expect do
click_button '削除'
end.to change(Post, :count).by(-1) # 削除ボタンをクリックするとPostが1つ減る
# リダイレクト後の画面確認
expect(current_path).to eq('/')
expect(page).to have_content('投稿が削除されました') # フラッシュメッセージを表示
expect(page).not_to have_link("/posts/#{@post.id}") # 削除した投稿(の詳細ページへのリンク)が存在しない
end
end
context '投稿したユーザーでログインしていない場合' do
it '削除ボタンを表示しない' do
visit "/posts/#{@post.id}"
expect(page).not_to have_button('削除')
end
it '直接リクエストを投げても削除されない' do
visit "/posts/#{@post.id}"
expect do
delete post_path(@post) # 投稿データを削除するリクエストを送る
end.not_to change(Post, :count)
end
end
end
describe 'ナビゲーションバーの検証' do
context 'ログインしていない場合' do
before { visit '/' }
it 'ログ一覧リンクを表示する' do
expect(page).to have_link('ログ一覧', href: '/')
end
it 'ログ投稿リンクを表示しない' do
expect(page).not_to have_link('ログ投稿', href: '/posts/new')
end
end
context 'ログインしている場合' do
before do
user = create(:user) # ログイン用のユーザーを作成
sign_in user # 作成したユーザーでログイン
visit '/'
end
it 'ログ一覧リンクを表示する' do
expect(page).to have_link('ログ一覧', href: '/')
end
it 'ログ投稿リンクを表示する' do
expect(page).to have_link('ログ投稿', href: '/posts/new')
end
end
end
end
</details>
ルーティングの変更
ではここから、テストが通るように変更を加えていきましょう。
まずはルーティングの設定からです。
root ('/'
) にアクセスした時に学習ログ一覧を表示させるため、ルーティング設定を変更します。
そのために、root 指定で呼ぶアクションを posts#index
に変更します。
config/routes.rb
Rails.application.routes.draw do
devise_for :users
root 'posts#index' # 修正
resources :posts, only: [:new, :create, :show, :destroy] # 修正
end
また、resources 内の :index
指定は不要になるので削除していることに注意してください。。
PostsController の変更
PostsController の create アクションと destroy アクションんでは、処理の成功時に投稿一覧へリダイレクトするようにしていました。
そのリダイレクト先の URL は posts_path
と指定していましたので、ここを root_path
に変更しておきます。
app/controllers/posts_controller.rb
def create
@post = Post.new(post_params)
@post.user_id = current_user.id # ログインユーザのIDを代入
if @post.save
flash[:notice] = '投稿しました'
redirect_to root_path # 修正
else
flash[:alert] = '投稿に失敗しました'
render :new
end
end
...
def destroy
@post = Post.find_by(id: params[:id])
if @post.user == current_user
@post.destroy
flash[:notice] = '投稿が削除されました'
end
redirect_to root_path # 修正
end
ナビゲーションバー内リンクの変更
最後に、ナビゲーションバーの「ログ一覧」リンクのパスも変更します。
ここも posts_path
で指定していたので root_path
に置き換えてあげましょう。
(修正前): source/techlog/saigen/app/views/shared/_navbar.html.erb
...
<%= link_to "ログ一覧", posts_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" %>
(修正後): source/techlog/saigen/app/views/shared/_navbar.html.erb
...
<%= link_to "ログ一覧", root_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" %>
Home 関連のファイル削除
Home に関するファイルは不要になるので、すべて削除します。
まずはControllerからです。
$ rm app/controllers/home_controller.rb
エディタの操作で削除しても OK です。
ファイルが削除されていることを確認してください。
次はView です。
ディレクトリごと削除します。
$ rm -rf app/views/home
最後にテストです。
Request Specも、System Spec も不要になった削除します。
$ rm spec/requests/home_spec.rb
$ rm spec/system/home_spec.rb
テスト実行
変更もすべて完了したので、すべてのテストに通ることを確認します。
$ bin/rspec
Finished in 12.2 seconds (files took 0.28092 seconds to load)
60 examples, 0 failures
変更をコミット
では今回の変更をコミットしておきましょう。
$ git add .
$ git commit -m "Home関連機能を削除"
$ git push
今回は変更点が多かったので大変かもしれませんが、テストが失敗することで修正漏れに気付けるようになっているので安心してください!