##[Follow]のWebインターフェイス
この節では、モックアップで示したようにフォロー/フォロー解除の基本的なインターフェイスを実装します。
フォローしているユーザーと、フォロワーにそれぞれ表示用のページを作成します。
ユーザーのステータスフィードを追加して、サンプルアプリケーションを完成させます。
###フォローのサンプルデータ
####サンプルデータにfollowing/followerの関係性を追加する
db/seeds.rb
.
.
.
# 以下のリレーションシップを作成する
users = User.all
# 全ユーザー
user = users.first
# 最初のユーザー
following = users[2..50]
# 全体の3(2+1)番目から51(50+1)番目まで呼び出す
followers = users[3..40]
# この場合 4番目から41番目まで呼び出す
following.each { |followed| user.follow(followed) }
# 「each」メソッドは配列や範囲オブジェクトなどで用意されているメソッドであり、オブジェクトに含まれている要素を順に取り出します。
# 配列から一つずつ取り出し、自分にフォローさせる。
followers.each { |follower| follower.follow(user) }
# それぞれのユーザーに自分をフォローさせる
###演習
1.
コンソールを開き、User.first.followers.countの結果がリスト 14.14で期待している結果と合致していることを確認してみましょう。
> User.first.followers.count
User Load (0.1ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? [["LIMIT", 1]]
(1.0ms) SELECT COUNT(*) FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."follower_id" WHERE "relationships"."followed_id" = ? [["followed_id", 1]]
=> 38
>> User.first.following.count
User Load (0.2ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? [["LIMIT", 1]]
(0.8ms) SELECT COUNT(*) FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."followed_id" WHERE "relationships"."follower_id" = ? [["follower_id", 1]]
=> 49
先ほどの演習と同様に、User.first.following.countの結果も合致していることを確認してみましょう。
1問目で解決
###統計と[Follow]フォーム
プロフィールページとHomeページを更新して、これを反映しましょう。
プロフィールページとHomeページに、フォローしているユーザーとフォロワーの統計情報を表示するためのパーシャルを作成します。
フォロー用とフォロー解除用のフォームを作成します。
フォローしているユーザーの一覧("following")とフォロワーの一覧("followers")を表示する専用のページを作成
####Usersコントローラにfollowingアクションとfollowersアクションを追加する
config/routes.rb
Rails.application.routes.draw do
.
.
.
member do
# member メンバールーティング(デフォルトで作成されるRESTfullなルーティング)を追加
get :following, :followers
# URLで指定したファイルの送信を要求するためのもの。コントローラやアクションを呼び出すこともある。
# :controller, :action コントローラとアクションを指定。必ずセットで指定
end
end
.
.
.
end
####フォロワーの統計情報を表示するパーシャル
app/views/shared/_stats.html.erb
<% @user ||= current_user %>
<!--<%...%> 埋め込みruby
@userにどちらかが返される-->
<div class="stats">
<!--クラス名-->
<a href="<%= following_user_path(@user) %>">
<!--<a href="リンク先のURL">アンカーテキスト</a>-->
<strong id="following" class="stat">
<!--<strong>~</strong>で囲んだテキストを強調-->
<%= @user.following.count %>
<!--フォローの数(強調された文字) これがアンカーテキストになる-->
</strong>
following
<!--これもアンカーテキスト
この場合フォロー数とfollwingがアンカーテキストとなる-->
</a>
<a href="<%= followers_user_path(@user) %>">
<strong id="followers" class="stat">
<%= @user.followers.count %>
</strong>
followers
</a>
</div>
###Homeページにフォロワーの統計情報を追加する
####app/views/static_pages/home.html.erb
<div class="row">
<aside class="col-md-4">
<section class="user_info">
<%= render 'shared/user_info' %>
<!--user_infoアクションに移動する-->
</section>
<section class="stats">
<%= render 'shared/stats' %>
</section>
<section class="micropost_form">
<%= render 'shared/micropost_form' %>
</section>
</aside>
<div class="col-md-8">
<h3>Micropost Feed</h3>
<%= render 'shared/feed' %>
</div>
</div>
####フォロワーの統計情報を表示するパーシャル
app/views/shared/_stats.html.erb
<% @user ||= current_user %>
<!--<%...%> 埋め込みruby
@userにどちらかが返される-->
<div class="stats">
<!--クラス名-->
<a href="<%= following_user_path(@user) %>">
<!--<a href="リンク先のURL">アンカーテキスト</a>-->
<strong id="following" class="stat">
<!--<strong>~</strong>で囲んだテキストを強調-->
<%= @user.following.count %>
<!--フォローの数(強調された文字) これがアンカーテキストになる-->
</strong>
following
<!--これもアンカーテキスト
この場合フォロー数とfollwingがアンカーテキストとなる-->
</a>
<a href="<%= followers_user_path(@user) %>">
<strong id="followers" class="stat">
<%= @user.followers.count %>
</strong>
followers
</a>
</div>
####Homeページにフォロワーの統計情報を追加する
app/views/static_pages/home.html.erb
<% if logged_in? %>
<%= render 'static_pages/user_logged_in' %>
<% else %>
<%= render 'static_pages/user_not_logged_in' %>
<% end %>
####Homeページのサイドバー用のSCSS
app/assets/stylesheets/custom.scss
.stats {
overflow: auto;
margin-top: 0;
padding: 0;
a {
float: left;
padding: 0 10px;
border-left: 1px solid $gray-lighter;
color: gray;
&:first-child {
padding-left: 0;
border: 0;
}
&:hover {
text-decoration: none;
color: blue;
}
}
strong {
display: block;
}
}
.user_avatars {
overflow: auto;
margin-top: 10px;
.gravatar {
margin: 1px 1px;
}
a {
padding: 0;
}
}
.users.follow {
padding: 0;
}
/* forms */
.
.
.
####フォロー/フォロー解除フォームのパーシャル
app/views/users/_follow_form.html.erb
<% unless current_user?(@user) %>
<!--ログインしてなないか?-->
<div id="follow_form">
<% if current_user.following?(@user) %>
<!--ログインされたユーザーは@userをフォローしているか?-->
<%= render 'unfollow' %>
<!--unfollowのパーシャルに移動-->
<% else %>
<%= render 'follow' %>
<% end %>
</div>
<% end %>
####Relationshipリソース用のルーティングを追加する
config/routes.rb
Rails.application.routes.draw do
get 'password_resets/new'
get 'password_resets/edit'
get 'sessions/new'
root 'static_pages#home'
# 何の意味がわからん
# ホーム画面がhomeページなるらしい
get '/help', to: 'static_pages#help'
# static_pagesコントローラからhomeアクションに紐付けされる
# getでアクセルすることでページを取得することができる
get '/about', to: 'static_pages#about'
# 何を書いているかはわからない
get '/contact', to: 'static_pages#contact'
# aboutアクションにGETリクエストを送る
get '/signup', to: 'users#new'
# urlに/signupと書くとuserコントローラのnewアクションを起こす
get '/login', to: 'sessions#new'
# データを取得
post '/login', to: 'sessions#create'
# データを投稿
delete '/logout', to: 'sessions#destroy'
# 削除
resources :users do
# usersコントローラ
member do
# member メンバールーティング(デフォルトで作成されるRESTfullなルーティング)を追加
get :following, :followers
# URLで指定したファイルの送信を要求するためのもの。コントローラやアクションを呼び出すこともある。
# :controller, :action コントローラとアクションを指定。必ずセットで指定
end
end
resources :users
# /users/1の有効にするため
resources :account_activations, only: [:edit]
# editアクションへの名前付きルートが必要になるため
# ルーティングのアカウント有効化
resources :password_resets, only: [:new, :create, :edit, :update]
# 新しいパスワードを再設定するためのフォームと、Userモデル内のパスワードを変更するため
resources :microposts, only: [:create, :destroy]
# マイクロポストにはcreate,destroyあれば十分
# RESTfulなルーティングのサブセットになります。
# サブセットとは、一部分、部分集合、下位集合などの意味を持つ英単語
resources :relationships, only: [:create, :destroy]
# ???
end
####ユーザーをフォローするフォーム
app/views/users/_follow.html.erb
<%= form_with(model: current_user.active_relationships.build, local: true) do |f| %>
<div><%= hidden_field_tag :followed_id, @user.id %></div>
<%= f.submit "Follow", class: "btn btn-primary" %>
<% end %>
####ユーザーをフォロー解除するフォーム
app/views/users/_unfollow.html.erb
<%= form_with(model: current_user.active_relationships.find_by(followed_id: @user.id),
html: { method: :delete }, local: true) do |f| %>
<%= f.submit "Unfollow", class: "btn btn-default" %>
<% end %>
####プロフィールページにフォロー用フォームとフォロワーの統計情報を追加する
app/views/users/show.html.erb
<% provide(:title, @user.name) %>
<div class="row">
<!--サイドバーを表示させる-->
<aside class="col-md-4">
<!--サイドバーを表示させる-->
<section class="user_info">
<h1>
<%= gravatar_for @user %>
<%= @user.name %>
</h1>
</section>
<section class="stats">
<%= render 'shared/stats' %>
<!--???-->
</section>
</aside>
<div class="col-md-8">
<%= render 'follow_form' if logged_in? %>
<!--フォローされているかを調べる-->
<% if @user.microposts.any? %>
.
.
.
</div>
```
###演習
1.
ブラウザから /users/2 にアクセスし、フォローボタンが表示されていることを確認してみましょう。同様に、/users/5 では[Unfollow]ボタンが表示されているはずです。さて、/users/1 にアクセスすると、どのような結果が表示されるでしょうか?
フォロー、アンフォローのボタンが無かった。
2.
ブラウザからHomeページとプロフィールページを表示してみて、統計情報が正しく表示されているか確認してみましょう。
確認
3.
Homeページに表示されている統計情報に対してテストを書いてみましょう。同様にして、プロフィールページにもテストを追加してみましょう。ヒント: リスト 13.28で示したテストに追加してみてください。
しなかった。