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 []>