###[Follow]ボタン Ajax編
####Ajaxを使ったフォローフォーム
app/views/users/_follow.html.erb
<%= form_with(model: current_user.active_relationships.build, remote: true) do |f| %> <div><%= hidden_field_tag :followed_id, @user.id %></div>
<%= f.submit "Follow", class: "btn btn-primary" %>
<% end %>
###Ajaxを使ったフォロー解除フォーム
app/views/users/_unfollow.html.erb
<%= form_with(model: current_user.active_relationships.find_by(followed_id: @user.id),
html: { method: :delete }, remote: true) do |f| %>
<%= f.submit "Unfollow", class: "btn btn-default" %>
<% end %>
####RelationshipsコントローラでAjaxリクエストに対応する
app/controllers/relationships_controller.rb
class RelationshipsController < ApplicationController
before_action :logged_in_user
# ログインされていることが前提
def create
user = User.find(params[:followed_id])
current_user.follow(user)
respond_to do |format|
format.html { redirect_to @user }
# リクエストされるフォーマットがHTML形式の場合
# @userにリダイレクト
format.js
end
end
def destroy
user = Relationship.find(params[:id]).followed
current_user.unfollow(user)
respond_to do |format|
format.html { redirect_to @user }
format.js
end
end
end
####JavaScriptが無効になっていたときのための設定
config/application.rb
require_relative 'boot'
require 'rails/all'
# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)
module SampleApp
class Application < Rails::Application
# Initialize configuration defaults for originally generated Rails version.
config.load_defaults 6.0
# Settings in config/environments/* take precedence over those specified here.
# Application configuration can go into files in config/initializers
# -- all .rb files in that directory are automatically loaded after loading
# the framework and any gems in your application.
# 認証トークンをremoteフォームに埋め込む
config.action_view.embed_authenticity_token_in_remote_forms = true
end
end
####JavaScriptと埋め込みRubyを使ってフォローの関係性を作成する
app/views/relationships/create.js.erb
$("#follow_form").html("<%= escape_javascript(render('users/unfollow')) %>");
$("#followers").html('<%= @user.followers.count %>');
####Ruby JavaScript(RJS)を使ってフォローの関係性を削除する
app/views/relationships/destroy.js.erb
$("#follow_form").html("<%= escape_javascript(render('users/follow')) %>");
$("#followers").html('<%= @user.followers.count %>');
###演習
1.
ブラウザから /users/2 にアクセスし、うまく動いているかどうか確認してみましょう。
確認
先ほどの演習で確認が終わったら、Railsサーバーのログを閲覧し、フォロー/フォロー解除を実行した直後のテンプレートがどうなっているか確認してみましょう。
わからなかった。
###フォローをテストする
####[Follow]/[Unfollow]ボタンをテストする
test/integration/following_test.rb
require 'test_helper'
class FollowingTest < ActionDispatch::IntegrationTest
def setup
@user = users(:michael)
# テストユーザー
@other = users(:archer)
log_in_as(@user)
# ログインさせる
end
test "following page" do
# followページに正確にフォッロワーが表示しているかどうかのテスト
get following_user_path(@user)
# ユーザーのフォロー数を表示させることを要求
assert_not @user.following.empty?
# ユーザーのフォローが0でないか確認?
assert_match @user.following.count.to_s, response.body
# フォロー数がユーザーページにあるかどうか確認?
@user.following.each do |user|
# ユーザーのフォローしているユーザー数を一つづつ取り出す
assert_select "a[href=?]", user_path(user)
# ひとつずつ取り出してaタグにユーザーが書かれているか?
end
end
test "followers page" do
get followers_user_path(@user)
assert_not @user.followers.empty?
assert_match @user.followers.count.to_s, response.body
@user.followers.each do |user|
assert_select "a[href=?]", user_path(user)
end
end
test "should follow a user the standard way" do
assert_difference '@user.following.count', 1 do
# フォローがひとつだけ増えたか確認
post relationships_path, params: { followed_id: @other.id }
end
end
test "should follow a user with Ajax" do
# Ajax用のテスト
assert_difference '@user.following.count', 1 do
post relationships_path, xhr: true, params: { followed_id: @other.id }
# xhr: true Ajaxでリクエストを発行するように変わります。
end
end
test "should unfollow a user the standard way" do
@user.follow(@other)
relationship = @user.active_relationships.find_by(followed_id: @other.id)
# フォローさせる
assert_difference '@user.following.count', -1 do
# フォローが一つだけ減ったか確認
delete relationship_path(relationship)
end
end
test "should unfollow a user with Ajax" do
@user.follow(@other)
relationship = @user.active_relationships.find_by(followed_id: @other.id)
assert_difference '@user.following.count', -1 do
delete relationship_path(relationship), xhr: true
end
end
end
###演習
1.
リスト 14.36のrespond_toブロック内の各行を順にコメントアウトしていき、テストが正しくエラーを検知できるかどうか確認してみましょう。実際、どのテストケースが落ちたでしょうか?
ERROR["test_should_follow_a_user_the_standard_way", #<Minitest::Reporters::Suite:0x00005639201cf5e8 @name="FollowingTest">, 6.431756742000005]
test_should_follow_a_user_the_standard_way#FollowingTest (6.43s)
ActionController::UnknownFormat: ActionController::UnknownFormat: RelationshipsController#create is missing a template for this request format and variant.
request.formats: ["text/html"]
request.variant: []
test/integration/following_test.rb:40:in `block (2 levels) in <class:FollowingTest>'
test/integration/following_test.rb:38:in `block in <class:FollowingTest>'
ERROR["test_should_unfollow_a_user_the_standard_way", #<Minitest::Reporters::Suite:0x000056392023fa78 @name="FollowingTest">, 6.489258220000011]
test_should_unfollow_a_user_the_standard_way#FollowingTest (6.49s)
ActionController::UnknownFormat: ActionController::UnknownFormat: RelationshipsController#destroy is missing a template for this request format and variant.
request.formats: ["text/html"]
request.variant: []
test/integration/following_test.rb:58:in `block (2 levels) in <class:FollowingTest>'
test/integration/following_test.rb:56:in `block in <class:FollowingTest>'
73/73: [===========================] 100% Time: 00:00:07, Time: 00:00:07
Finished in 7.62512s
73 tests, 338 assertions, 0 failures, 2 errors, 0 skips
リスト 14.40のxhr: trueがある行のうち、片方のみを削除するとどういった結果になるでしょうか? このとき発生する問題の原因と、なぜ先ほどの演習で確認したテストがこの問題を検知できたのか考えてみてください。
わからない。