TwitterやInstagramなどの友達をフォローする機能を実装してみました。
#1.relationshipモデルの作成
$ rails g model Relationship follower_id:integer following_id:integer
invoke active_record
create db/migrate/20170102050943_create_relationships.rb
create app/models/relationship.rb
invoke test_unit
create test/models/relationship_test.rb
create test/fixtures/relationships.yml
#2.マイグレーションファイルの編集
db/migrate/...
class CreateRelationships < ActiveRecord::Migration
def change
create_table :relationships do |t|
t.integer :follower_id
t.integer :following_id
t.timestamps
end
add_index :relationships, :follower_id
add_index :relationships, :following_id
add_index :relationships, [:follower_id, :following_id], unique: true
end
end
$ bundle exec rake db:migrate
#3.relationshipモデルとuserモデルの編集
app/models/relationship.rb
class Relationship < ActiveRecord::Base
belongs_to :follower, class_name: "User"
belongs_to :following, class_name: "User"
validates :follower_id, presence: true
validates :following_id, presence: true
end
app/models/user.rb
class User < ActiveRecord::Base
# 省略
has_many :following_relationships, foreign_key: "follower_id", class_name: "Relationship", dependent: :destroy
has_many :followings, through: :following_relationships
has_many :follower_relationships, foreign_key: "following_id", class_name: "Relationship", dependent: :destroy
has_many :followers, through: :follower_relationships
def following?(other_user)
following_relationships.find_by(following_id: other_user.id)
end
def follow!(other_user)
following_relationships.create!(following_id: other_user.id)
end
def unfollow!(other_user)
following_relationships.find_by(following_id: other_user.id).destroy
end
end
#4.ビューファイルの編集
app/views/users/show.html.erb
<span id="user_<%= @user.id %>" class="follow-wrapper">
<%= render 'follow_form', user: @user if signed_in? %>
</span>
app/views/users/_follow_form.html.erb
<% unless current_user.id == user.id %>
<% if current_user.following?(user) %>
<%= render 'users/unfollow', user: user %>
<% else %>
<%= render 'users/follow', user: user %>
<% end %>
<% end %>
app/views/users/_follow.html.erb
<%= form_for(current_user.following_relationships.build(following_id: user.id),
remote: true) do |f| %>
<div><%= f.hidden_field :following_id %></div>
<%= f.submit "Follow", class: "btn btn-large btn-primary" %>
<% end %>
app/views/users/_unfollow.html.erb
<%= form_for(current_user.following_relationships.find_by(following_id: user.id),
html: { method: :delete },
remote: true) do |f| %>
<%= f.submit "Unfollow", class: "btn btn-large" %>
<% end %>
#5.routeの設定
config/routes.rb
resources :users do
member do
get :following, :followers, :users_tweets
end
end
resources :relationships, only: [:create, :destroy]
#6.コントローラーの設定
$ rails g controller relationships
app/controllers/relationships_controller.rb
def create
@user = User.find(params[:relationship][:following_id])
current_user.follow!(@user)
respond_to do |format|
format.html { redirect_to @user }
format.js
end
end
def destroy
@user = Relationship.find(params[:id]).following
current_user.unfollow!(@user)
respond_to do |format|
format.html { redirect_to @user }
format.js
end
end
app/controllers/users_controller.rb
def following
@title = "フォロー"
@user = User.find(params[:id])
@users = @user.followings
render 'show_follow'
end
def followers
@title = "フォロワー"
@user = User.find(params[:id])
@users = @user.followers
render 'show_follow'
end
#7.ビューファイルの編集
app/views/users/show.html.erb
<h4>
<%= render 'users/stats' %>
</h4>
app/views/users/_stats.html.erb
<% @user ||= current_user %>
<div class="stats">
<a href="<%= following_user_path(@user) %>">
<strong id="following" class="stat">
<%= @user.followings.count %>
</strong>
フォロー
</a>
<a href="<%= followers_user_path(@user) %>">
<strong id="followers" class="stat">
<%= @user.followers.count %>
</strong>
フォロワー
</a>
</div>
app/views/users/show_follow.html.erb
<div class="row">
<aside class="span4">
<section>
<%= render 'users/stats' %>
<h2><%= @title %></h2>
<% if @users.any? %>
<% @users.each do |user| %>
<div class="user_avatars">
<span><img src="<%= user.avatar.url(:thumb) %>"></span><br />
<%= link_to user.username ,user_path(user) %>
</div>
<% end %>
<% end %>
</section>
</aside>
</div>
#8.jsファイルの編集
app/views/relationships/create.js.erb
$("#user_<%= @user.id %>").html("<%= escape_javascript(render('users/follow_form', user: @user)) %>")
$("#followers").html('<%= @user.followers.count %>')
app/views/relationships/destroy.js.erb
$("#user_<%= @user.id %>").html("<%= escape_javascript(render('users/follow_form', user: @user)) %>")
$("#followers").html('<%= @user.followers.count %>')