1

Railsアプリ用のFacebookスタイルのメッセージングシステムを作成していますが、受信トレイのメッセージを選択するのに問題があります(will_paginateを使用)。

メッセージはスレッドで編成され、受信ボックスにはスレッドの最新のメッセージがそのスレッドへのリンクとともに表示されます。スレッドは、それ自体とのparent_id1-n関係を介して編成されます。

これまでのところ、私は次のようなものを使用しています:

class Message < ActiveRecord::Base
  belongs_to :sender, :class_name => 'User', :foreign_key => "sender_id"
  belongs_to :recipient, :class_name => 'User', :foreign_key => "recipient_id"
  has_many :children, :class_name => "Message", :foreign_key => "parent_id"
  belongs_to :thread, :class_name => "Message", :foreign_key => "parent_id"
end

class MessagesController < ApplicationController

  def inbox
    @messages = current_user.received_messages.paginate :page => params[:page], :per_page => 10, :order => "created_at DESC"
  end
end

これですべてのメッセージが表示されますが、1つのスレッドについては、スレッド自体と最新のメッセージ(および最新のメッセージだけでなく)が表示されます。もちろん、スレッド自体(いわば親)の場合、parent_id = nilであるため、GROUPBY句を使用することもできません。

誰かがこれをエレガントな方法で解決する方法についてアイデアを得ましたか?親自体にparent_idを追加してから、parent_idでグループ化することをすでに考えましたが、それが機能するかどうかはわかりません。

ありがとう

4

5 に答える 5

0

唯一の良い解決策は、すべてのスレッドの最新のメッセージを格納するために2番目のモデルを使用することであると考えました(副選択でGROUP BYを使用する場合のパフォーマンスの問題のため、私のコメントを参照してください)。IDのみを保存し、テキストやBLOBを保存しないため、DBに多くのスペースを必要としません。

最近のメッセージモデルは次のようになります。

create_table :recent_messages do |t|
  t.integer :sender_id
  t.integer :recipient_id
  t.integer :message_id
  t.integer :message_thread_id

  t.timestamps
end

class RecentMessage < ActiveRecord::Base

  belongs_to :message
  belongs_to :message_thread, :class_name => 'Message'
  belongs_to :sender, :class_name => 'User', :foreign_key => "sender_id"
  belongs_to :recipient, :class_name => 'User', :foreign_key => "recipient_id"

end

主なアイデアは次のとおりです。すべてのメッセージは1つのモデル(メッセージ)に保存されます。新しいメッセージがスレッドに追加される(またはスレッドが作成される)たびに、2つのことが起こります(たとえば、after_saveコールバックを使用する場合)。

  • 新しいメッセージをRecentMessagesモデルに保存します(つまり、sender_id、recipient_id、message_id、message_thread_id(= parent_id || id))
  • (メッセージ内のこのスレッドから)最新のメッセージを取得します。ここで、sender_id == receive_idおよびその逆(注:これは、メッセージモデルが2人のユーザー間のメッセージのみをサポートする必要がある場合にのみ機能します)、RecentMessagesモデルにも保存します(if見つかりました。まだ存在しない場合)

もちろん、最大である必要があります。任意の時点ですべてのmessage_threadに対してDBに保存されている2つのrecent_messages。

受信トレイなどを表示したい場合は、次のことを行う必要があります。

@messages = current_user.recent_received_messages.paginate :page => params[:page], :per_page => 10, :order => "created_at DESC", :include => :message

それは私がこれまでに理解した中で最高です。まだ醜いと思いますが、速くて動作します。誰かがより良い解決策を思いついたら、私は感謝します!

于 2009-06-03T08:57:42.930 に答える
0

唯一の効率的な方法は、Thread モデルを使用し、前述のように GROUP BY を使用することです。それ以外の場合は、メッセージの反復が必要になります。

コメントで更新を読む

于 2009-05-31T20:11:56.477 に答える
0

Railsでこれを達成する方法はわかりませんが、MySQLで直接行った方法は次のとおりです。

select * from messages where message_id in ( select max(message_id) from messages where to_uid = 51 group by thread_id ) order by timestamp desc

サブクエリを使用してスレッド内の最新のメッセージを取得し、次にメイン クエリを使用してサブクエリで見つかったメッセージのすべてのフィールドを取得しました。

于 2010-05-20T01:09:23.990 に答える
0

私の解決策は、スレッドのリストを取得することです (これは、親 ID のないメッセージによって取得できると想定しています)。次に Message モデルに、スレッド内の最新のメッセージを見つけて返すメソッドを追加します。次に、そのメソッドを使用して各スレッドの最新のメソッドを取得し、スレッドの先頭へのリンクを簡単に配置できます。

(疑似) コード:

class Message < ActiveRecord::Base
  belongs_to :sender, :class_name => 'User', :foreign_key => "sender_id"
  belongs_to :recipient, :class_name => 'User', :foreign_key => "recipient_id"
  has_many :children, :class_name => "Message", :foreign_key => "parent_id"
  belongs_to :thread, :class_name => "Message", :foreign_key => "parent_id"

  def get_last_message_in_thread()
    last_message = self
    children.each do |c|
       message = c.get_last_message_in_thread()
       last_message = message if message.created_at > last_message.created_at
    end
    return last_message
  end
end

class MessagesController < ApplicationController

  def inbox
    @messages = current_user.received_messages.find_by_parent_id(Null).paginate :page => params[:page], :per_page => 10, :order => "created_at DESC"
  end
end

スレッド内の最後のメッセージを見つけるために再帰関数を使用するよりもはるかにうまくいく可能性がありますが、これはアイデアを実証するために私が考えることができる最も簡単な解決策です。また、受信トレイ関数で未設定の親IDを見つけるための正しい構文があるかどうかもわかりません。そのため、コードを疑似コードとしてマークしました:)

于 2009-05-31T19:44:39.167 に答える
0

親自体を親として指定すると、parent_id でグループ化 (または同様のもの) できるため、スレッド全体で動作するクエリを非常に簡単に作成できます。

親を別の方法で処理する場合、すべてのクエリでこれも処理する必要があります

于 2009-05-31T20:19:20.347 に答える