id:NeoCat:20080525に引き続き monologue (Twitterもどき)を作っていきます。
特定のユーザの最新の発言を取得するにはどうすれば良いでしょうか。
まず思いつくのは、そのまま「あるユーザのステータスを日付順に並べたときに、一番最初のもの」と記述する方法です。
findで書くと下のような感じでしょうか。
new_status = Status.find(:first,:conditions => [ "id = ?", @user.id], :order => "updated_at DESC")
もしくはfind_byで
new_status = Status.find_by_user_id(@user.id, :order => "updated_at DESC", :limit => 1)
など。
しかし、例えばフォロワーの一覧に最新ステータスを並べたい場合など、ユーザごとにこの検索を行っていると、とても遅そうです。
インデックスの作成などDB側の工夫でもある程度は早くなるでしょうが、最新の1件(もしくはn件)だけ表示できれば良い場合、発言時にusersテーブルの中にフィールドを追加し、そこに最新のStatusのIDを記録してしまうという方法が考えられます。
ただし発言の削除時は、気をつけないと、存在しないIDを指し示すことになってしまいます。これを回避するには、削除時に最新の発言を改めて検索して、フィールドを更新すれば良さそうです。
というわけで、実装してみたのが以下のコントローラ。
def new if logged_in? && request.post? @status = Status.new(params[:status]) <snip> current_user.statuses << @status current_user.new_status = @status.id #追加 current_user.save! #追加 flash[:notice] = "更新しました!" <snip> redirect_to(:controller => :user, :action => 'index') end def delete @status = params[:id] && Status.find(params[:id]) if @status && @status.user == current_user @status.destroy flash[:notice] = "削除しました!" new_status = Status.find_by_user_id(current_user.id, :limit => 1, :order => "updated_at DESC") #追加 current_user.new_status = new_status ? new_status.id : nil #追加 current_user.save! #追加 <snip> end
以前作ったStatusコントローラに上記のコメント部分で示したを追加しました。
なお、あらかじめMigrationなどを使ってusersテーブルにはあらかじめnew_statusフィールドを追加しておきます。やり方はこの記事などを参照。
こうしておけば、Status.find(@user.new_status) で素早く最新のStatusが取得できます。