2

私はRailsの初心者で、mysqlで左結合を実行しようとしています。

ユーザーとメッセージの2つのオブジェクトがあります。

ユーザーhas_and_belongs_to_manyメッセージ、メッセージhas_and_belongs_to_manyユーザー

現在、user.messagesと書くだけで、コンソールで次のクエリを取得できます

SELECT * FROM `messages` INNER JOIN `messages_users` ON `messages`.id = `messages_users`.message_id WHERE (`users_messages`.group_id = 1 )

制限付きのメッセージ==falseはどのユーザーにも接続されていませんが、すべてのユーザーがアクセスできます。コレクションMessage.all(restricted => false)をuser.messagesに追加する必要があります。

私の問題を解決するクエリは次のようになります。

select * from messages left join messages_users on messages_users.message_id=messages.id and messages_users.user_id=1 where (messages_users.user_id is NULL and messages.restricted=false) OR (messages_users.user_id=1 and messages.restricted=true);

できるだけエレガントにレールに書き込むにはどうすればよいですか?

それはsmthのようになりますか

Message.find(:all,:conditions => "(messages_users.user_id is NULL and messages.restricted=false) OR (messages_users.user_id=1 and messages.restricted=true)", :joins => "left join messages_groups on messages_users.message_id=messages.id and messages_users.user_id=1 " )

それとももっといいですか?

レールを使用しています2.3.2

ありがとう、パベル

4

3 に答える 3

1

なぜ :include を使用しないのですか?

于 2009-08-10T12:04:14.947 に答える
1

そのクエリで 2 つのことを取得しようとしているように思えます: 1) 制限付き = false でユーザーに関連付けられていないすべてのメッセージと 2) 制限付き = true で現在のユーザーに関連付けられているすべてのメッセージ。

私がそれを正しく理解している場合、単一のクエリとして実行したい場合、それを行うためのより良い方法はわかりません。ただし、クエリを 2 つにすることを受け入れる場合は、コードでわずかにクリーンアップできます (ただし、実行が遅くなる可能性があります)。代替セットアップは次のとおりです。

class Message < ActiveRecord:Base
  has_and_belongs_to_many :users

  named_scope :restricted, :conditions => {:restricted => true}
  named_scope :unrestricted, :conditions => {:restricted => false}
  named_scope :public, :conditions => "id NOT IN (SELECT DISTINCT message_id FROM messages_users)"
end

class User < ActiveRecord:Base
  has_and_belongs_to_many :messages
end

より少ないコードでリストを取得するには、データベースに 2 回ヒットする必要があります。

@current_user.messages.restricted + Message.unrestricted.public

どちらの場合でも、これらのテーブルにかなりの量のデータがある場合は、適切にインデックスが作成されていることを確認する必要があります。そうしないと、負荷がかかると速度が低下します。これが多数のメッセージが送信されるアプリである場合は、単一のクエリを使用する方がよいでしょう。あまり使用されない単なる副次的な機能であれば、おそらくよりクリーンなバージョンを使用するでしょう。

モデルの観点からおそらくうまくいくのは、HABTM 関係を取り除き、関係を明示的にモデル化することです。次に、メッセージの送信/配信/受信プロセスに関する他のデータを追跡するための便利な場所があります (送信時間、読み取り時間などの追跡など)。上記の議論のいずれも変更しません。私は、HABTM までの多くの方法を好むだけです。

class Message < ActiveRecord:Base

  has_many :subscriptions
  has_many :users, :through => :subscriptions

  named_scope :restricted,   :conditions => {:restricted => true}
  named_scope :unrestricted, :conditions => {:restricted => false}
  named_scope :public, :conditions => "id NOT IN (SELECT DISTINCT message_id FROM subscriptions)"
end

class User < ActiveRecord:Base

  has_many :subscriptions
  has_many :messages, :through => :subscriptions

end

class Subscription < ActiveRecord:Base

  belongs_to :message
  belongs_to :user

end
于 2009-08-12T19:49:20.290 に答える
0

named_scopes があなたの答えかもしれないと思います。モデルに次のようなものを入れます:

named_scope :restricted,   :conditions => {:restricted => true}
named_scope :unrestricted, :conditions => {:restricted => false}

次に、次のようなものを呼び出すことができます。

Message.restricted
=> All restricted messages

User.first.messages.unrestricted
=> All unrestricted messages belonging to the first user.

これらは HABTM アソシエーションを通じて機能すると考えています。

于 2009-08-10T11:18:26.367 に答える