【Rails】フォロー機能を非同期で(Ajax)

ユーザーがある前提で進めていく。

手順

t.index [:follower_id, :followed_id], unique: true

連打したとき等に、ユーザーを2回以上フォローしないよう一意にする

Relationshipモデルを作成

Terminal
rails g model Relationship
20191015102954_create_relationships.rb
t.integer :follower_id
t.integer :followed_id
t.index [:follower_id, :followed_id], unique: true
Terminal
rails db:migrate

アソシエーション

app/models/user.rb
has_many :followed_relationships, foreign_key: "follower_id", class_name: "Relationship",  dependent: :destroy
has_many :followed, through: :followed_relationships
app/models/relationship.rb
belongs_to :follower, class_name: "User"
belongs_to :followed, class_name: "User"
validates :follower_id, presence: true
validates :followed_id, presence: true

Userモデルにメソッドを追加

followed?(user)

ユーザーをフォローしているかどうか判定するメソッド

下にも書いてあるが、viewはこんな感じ <% if current_user.followed?(@user) %>

follow(user)unfollow(user)

フォロー、フォロー解除する時のメソッド

app/models/user.rb
def followed?(user)
  followed_relationships.find_by(followed_id: user.id)
end

def follow(user)
  followed_relationships.create!(followed_id: user.id)
end

def unfollow(user)
  followed_relationships.find_by(followed_id: user.id).destroy
end

View(users)を編集

app/views/users/show.html.erb
<%= render "follow_form" %>

フォロー、フォロー解除ボタンを内包したパーシャル

app/views/users/_follow_form.html.erb
<% if user_signed_in? && @user != current_user %>
  <div id="follow_form">
    <% if current_user.followed?(@user) %>
      <%= render "unfollow" %>
    <% else %>
      <%= render "follow" %>
    <% end %>
  </div>
<% end %>

フォローボタン

app/views/users/_follow.html.erb
<%= form_for(current_user.followed_relationships.build, remote: true) do |f| %>
  <%= hidden_field_tag :followed_id, @user.id %>
  <%= f.submit "フォローする" %>
  <%= Relationship.where(followed_id: params[:followed_id]).size %>
<% end %>

フォロー解除ボタン

app/views/users/_unfollow.html.erb
<%= form_for(current_user.followed_relationships.find_by(followed_id: @user.id), html: { method: :delete }, remote: true) do |f| %>
  <%= f.submit "フォロー解除" %>
  <%= Relationship.where(followed_id: params[:followed_id]).size %>
<% end %>

relationshipsコントローラを作成、アクション追加

Terminal
rails g controller relationships

フォロー(create)とフォロー解除(destroy)した時のアクションを定義

format.html { redirect_to @user }

@userにリダイレクト

format.js

createアクションが走ったらcreate.js.erb、destroyアクションが走ったらdestroy.js.erbを表示

renderを省略しているため、デフォルトであるコントローラーアクション名と同名のテンプレートをレンダーする(Ajaxを使わない時と同じ)

app/controllers/relationships_controller.rb
def create
  @user = User.find(params[:followed_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]).followed
  current_user.unfollow(@user)
  respond_to do |format|
    format.html { redirect_to @user }
    format.js
  end
end

ルーティング

config/routes.rb
resources :relationships, only: [:create, :destroy]

View(relationships)を編集

先程定義したアクションが走った時に表示させるviewファイル

フォローした時に表示されてほしいのは解除ボタンだから、render(“users/unfollow”)でusers/_unfollow.html.erbを呼ぶ

フォローしていない時(解除した時)に表示されてほしいのはフォローボタンだから、render(“users/follow”)でusers/_follow.html.erbを呼ぶ

(“#followForm”) のidと users/_follow_form.html.erbのidを紐付ける

app/views/relationships/create.js.erb
$("#followForm").html("<%= j(render("users/unfollow")) %>");
app/views/relationships/destroy.js.erb
$("#followForm").html("<%= j(render("users/follow")) %>");

参考にしたサイト

rails ajaxでフォロー機能 - Qiita
フォロー機能作成までは割愛。 非同期処理のajaxを使ったフォローの実装。 自分用のメモなのでわかりにくいです。 ```show.html.erb <%= render 'follow_form' %&gt...
railsでフォロー機能をつける。 - Qiita
メモ ```:環境 rails 5.0.0 ログイン機能は、deviseで作っている。 ``` ###フォロー機能つける前の状態         deviseで、userモデルを作っている。パスワード以下の項目は省略 |...
タイトルとURLをコピーしました