LoginSignup
24
24

More than 5 years have passed since last update.

Ruby on Rails ~フォロー(友達申請)機能の実装(コードメモ)

Last updated at Posted at 2017-01-02

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>
  &nbsp;
  <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 %>')
24
24
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
24
24