2008-11-16 Railsで作るTwitterもどき
■[Rails] Railsで作るTwitterもどき(序)
吉見さんのスクリーンキャストから1年近くたった。
Ruby on Railsで10分で作るTwitterもどき - スクリーンキャスト - ZDNet Japan
ということで、初心者向けにスクリーンキャストだけではちょっと分からない部分について書いてみようかと。
モデル設計などはなるべく沿うつもりで。
■[Rails] Railsで作るTwitterもどき(下準備編)
とりあえず、今回は認証回りについてはログインができれば良いということで作る。
$ rails rtwitter
でプロジェクトを作って、以下、ユーザモデルや認証部分の作成は、
を参考にどうぞ。
■[Rails] Railsで作るTwitterもどき(モデル編)
ではモデル設計から。
- ユーザはつぶやきができる
- ユーザは他のユーザをフォローできる (あなたがフォロー)
- 他のユーザも自分をフォローできる (あなたをフォロー)
とりあえず、つぶやきについては後回しにするとして、フォローについてモデルだけ作ってしまおう。
上は簡略化した図だが、ここでは自分がフォローしている人達をfriends、自分をフォローしてくれている人達をfollowersと表すことにする。
ユーザとフォロワーは多対多の関係となる。Railsで多対多の関連を張る場合には、関連テーブルを間に挟む方法が取られる。この関連テーブルをFriendshipとしておく。
関連テーブル作成
$ ./script/generate model Friendship user_id:integer friend_id:integer
たいていのhas_many :throughだと、モデルの左右から関連を張らなければいけない場合が多いのだが、まずは、図でいうと左から右の、片側だけ関連を張ることにする。関連は必ず両方から張らなければいけないものではないので、このように片側だけ張るということもある。
関連名は下図のように、Userから見たhas_manyの方をfriendships, Friendshipから見たbelongs_toをfriendとする。
# app/models/user.rb class User < ActiveRecord::Base has_many :friendships, :dependent => :destroy # 以下略 end
":dependent => :destroy" で、ユーザが消えたら関連テーブルも消すようにしておく。
# app/models/friendship.rb class Friendship < ActiveRecord::Base belongs_to :user belongs_to :friend, :class_name => 'User', :foreign_key => :friend_id end
Rails初心者だと、関連名はテーブル名の単数形をアンダースコア化したものじゃないと付けられないとか、foreign_keyもテーブル名の単数形_idじゃないといけないとか思いがちだが、別にそんなことはない。自由に付けられる。
上の friendという関連も、関連先のクラスはUserで、外部キーはfriend_idにしている。
ここまで普通にhas_many, belongs_toの関連が張れたら、has_many :throughの関連をUserモデルに追加する。
# app/models/user.rb class User < ActiveRecord::Base # あなたがフォロー has_many :friendships, :dependent => :destroy has_many :friends, :through => :friendships # 追加 # 略 end
これで、ユーザに対して friendsという関連が張られ、current_user.friendsとすることで、自分がフォローしているユーザ(「あなたがフォロー」)が取得できるようになった。
この状態で他のユーザをフォローするには、friendsにフォローしたいユーザモデルを追加する方法と、関連テーブルを直接作る方法とがある。これは状況に応じて使い分けると良い。
# 関連にモデルを追加 current_user.friends << user # または関連テーブルを直接つくる Friendship.create(:user_id => current_user.id, :friend_id => user.id)
片側の関連が張れたので、今度は逆側の関連を張ろう。
逆側の関連を張ることで、「あなたをフォロー」のユーザ一覧が取得できるようになる。
逆からの関連名は、followershipsとuserで。
Userモデルに関連を追加する。
# app/models/user.rb class User < ActiveRecord::Base # あなたがフォロー has_many :friendships, :dependent => :destroy has_many :friends, :through => :friendships # あなたをフォロー has_many :followerships, :class_name => 'Friendship', :foreign_key => :friend_id, :dependent => :destroy # (1) has_many :followers, :through => :followerships, :source => :user # (2) # 略 end
まず (1) から。
関連名(:followerships)とクラス名(Friendship)が異なっているので、:class_nameでクラス名を指定。foreign_key は:friend_idを使う。
次に(2)。
":source => :user" の部分には、関連テーブルから先のモデルにアクセスするための(関連モデルから見た)関連名を入れる。ここでは、Friendshipモデルからその先のユーザ(user_idで繋がっている)に行くための関連名のシンボル :userを入れておく。
これで逆側の関連も張れた。
current_user.followers で、自分をフォローしているユーザの一覧が取得できる。
では次に、つぶやきについて見てみよう。
- ユーザはつぶやきができる (User has_many Tweets)
なので、そのまま has_many で関連を張ることにする。これは簡単。
もしも、「お気に入り」を実装するのであれば、下図のように関連テーブルを使うのもひとつの手だ。
ここではそのように作ってみる。つぶやき(Tweet)モデルと、お気に入りの関連モデル(Favoriteship)を作成。
$ ./script/generate model Tweet user_id:integer body:string $ ./script/generate model Favoriteship user_id:integer tweet_id:integer
関連を張る。
まずユーザ。
# app/models/user.rb class User < ActiveRecord::Base # あなたがフォロー has_many :friendships, :dependent => :destroy has_many :friends, :through => :friendships # あなたをフォロー has_many :followerships, :class_name => 'Friendship', :foreign_key => :friend_id, :d ependent => :destroy has_many :followers, :through => :followerships, :source => :user # つぶやき has_many :tweets, :dependent => :destroy # お気に入り has_many :favoriteships, :dependent => :destroy has_many :favorite_tweets, :through => :favoriteships, :source => :tweet # 略 end
次につぶやき。
# app/models/tweet.rb class Tweet < ActiveRecord::Base belongs_to :user has_many :favoriteships, :dependent => :destroy has_many :favorite_users, :through => :favoriteships, :source => :user end
最後はお気に入り。
class Favoriteship < ActiveRecord::Base belongs_to :user belongs_to :tweet end
お気に入りの追加や参照は以下のようにする。
# 自分のお気に入りを参照 current_user.favorite_tweets # お気に入りを追加 current_user.favorite_tweets << tweet # あるつぶやきをお気に入りにしているユーザを取得 tweet.favorite_users
これで、Twitterもどきに必要なフォローの関連と、つぶやき、お気に入りの関連を張ることができた。