みかづきメモ

学習したことのメモとか、日記とか、備忘録。

Rails でフォロー機能を実装したい

すでに情報が腐るほどあるフォロー機能ですが、理解を深めるためにも、
自分の言葉でまとめ直してみます。


Rails で、 Twitter や app.net などにある、ユーザーどうしのフォロー機能を
実装したいとします。
どうやら、いい感じの gem が存在しているようですが、今回は使わない方針で。

フォロー機能を実装しようと思うと、ユーザーとユーザーの多対多の関係となるため、
以下の様な DB 構成になると思います。
(Relation は中間テーブル)

 User                Relation                  User 
+----------------+  +--------------------+  +-------
| id:   integer  |  | target_id: integer |  | id: 
| name: string   +--+ from_id:   integer +--+ name:
| ...            |  |                    |  | ...
+----------------+  +--------------------+  +-------

UserA(id:1)UserB(id:2) をフォローした場合は、
Relationtarget_id: 2, from_id: 1 が挿入される感じです。

ということで、早速実装。
モデルを作って。

$ rails g model relation

マイグレーションファイルをいじる。

# @ db/migration/20160201094212_create_relations.rb
class CreateRelations < ActiveRecord::Migration
  def change
    create_table :relations do |t|
      t.integer target_id, null: false
      t.integer from_id,   null: false
    end
  end
end

そして適用。

$ bundle exec rake db:migrate

次に、 Model に has_many とかつけていきます。

# @ app/models/user.rb
class User < ActiveRecord::Base
  has_many :follows_f, class_name: 'Relation', foreign_key: :from_id
  has_many :followings, through: :follows_f, source: 'target'
  
  has_many :followers_f, class_name: 'Relation', foreign_key: :target_id
  has_many :followers, through: :followers_f, source: 'from'
 
  # ...
end

中間テーブルも。

# @ app/models/relation.rb
class Relation < ActiveRecord::Base
  belongs_to :target, class_name: 'User', foreign_key: 'target_id'
  belongs_to :from, class_name: 'User', foreign_key: 'from_id'
end

これで、上に示した DB の関連を実装できました。
次に、フォローなどの機能を追加していきます。

# @ app/models/user.rb
class User < ActiveRecord::Base
  ...
  
  def follow user
    followings << user
  end
  
  def unfollow user
    followings.destroy user
  end
  
  def followed? user
    followings.include? user
  end
  
  def follower? user
    user.followers.include? user
  end
end

これでおわり。