Rails

Railsにフォロー機能などを実装してみる

More than 3 years have passed since last update.

RailsでフォローやブロックといったSNS的な機能を実装すると、関連の定義などでモデルが肥大化したりとやや面倒。
この機能をモジュールとして提供してくれる acts_in_relation というGemを導入してみたのでメモ。

※ 内容はほぼ README のものです

準備

まずサンプルアプリケーションを生成する。

$ rails new sample 

acts_in_relation を追加する。

gem 'acts_in_relation'

インストールする。

$ bundle

手順

ここではユーザ同士のフォローについて書く。
(ユーザが記事にいいねをつける、など他モデルとの関連も実装できるが、そちらは README を参照のこと)

1. モデルを生成する

$ rails g model User name:string
$ rails g model Follow user_id:integer target_user_id:integer

2. インデックスを張る

class CreateFollows < ActiveRecord::Migration
  def change
    create_table :follows do |t|
      t.integer :user_id
      t.integer :target_user_id
      t.timestamps
    end

    add_index :follows, [:user_id, :target_user_id], unique: true
  end
end

3. acts_in_relation メソッドを書く

class User < ActiveRecord::Base
  acts_in_relation with: :follow
end

class Follow < ActiveRecord::Base
  acts_in_relation :action, source: :user, target: :user
end

以上で、以下のインスタンスメソッドが追加される。

  • user.follow(other_user)
  • user.unfollow(other_user)
  • user.following?(other_user)
  • user.following
  • other_user.followed_by?(user)
  • other_user.followers

例えば、以下のような動きになる。

user       = User.create(name: 'foo')
other_user = User.create(name: 'bar')

# Follow
user.follow other_user
user.following?(other_user)   #=> true
user.following                #=> <ActiveRecord::Associations::CollectionProxy [#<User id: 2, name: "bar", created_at: "2015-01-10 01:57:52", updated_at: "2015-01-10 01:57:52">]>
other_user.followed_by?(user) #=> true
other_user.followers          #=> <ActiveRecord::Associations::CollectionProxy [#<User id: 1, name: "foo", created_at: "2015-01-10 01:57:42", updated_at: "2015-01-10 01:57:42">]>

# Unfollow
user.unfollow other_user
user.following?(other_user)   #=> false
user.following                #=> <ActiveRecord::Associations::CollectionProxy []>
other_user.followed_by?(user) #=> false
other_user.followers          #=> <ActiveRecord::Associations::CollectionProxy []>