7

私は以下のモデルを持っています。ユーザーには UserAction があり、可能な UserAction の 1 つは ContactAction です (UserAction はポリモーフィズムです)。LoginActionなどの他のアクションがあります。

クラス User < AR::Base
  has_many :contact_requests, :class_name => "ContactAction"
  has_many :user_actions
  has_many_polymorphs :user_actionables, :from => [:contact_actions, ...], :through => :user_actions
 終わり

クラス UserAction < AR::Base
 所属先:ユーザー
 所属先 :user_actionable, :polymorphic => true
終わり

class ContactAction < AR::Base
 所属先:ユーザー
 named_scope :保留中、...
 named_scope :active, ...
終わり

この考え方は、ContactAction が 2 人のユーザーを結合し (アプリ内で他の結果を伴う)、常に受信側と送信側があるというものです。同時に、ContactAction はさまざまな状態 (期限切れ、保留中など) を持つことができます。

ユーザーが送信または受信したすべての保留中/期限切れの要求を言う@user.contact_actions.pending@user.contact_requests.expired、リストすることができます。これはうまくいきます。

私が今欲しいのは、両方のタイプの ContactActionに参加する方法です。すなわち@user.contact_actions_or_requests。私は次のことを試しました:

クラス ユーザー

 def contact_actions_or_requests
  self.contact_actions + self.contact_requests
 終わり

 # また
 has_many :contact_actions_or_requests, :finder_sql => ..., :counter_sql => ...

終わり

@user.contact_actions_or_requests.find(...)しかし、これらのすべてには、関連付けの上に追加のファインダーまたはnamed_scopes を使用できないという問題があります@user.contact_actions_or_requests.expired

基本的に、2 つの異なるパスを持つ 1:n の関連付けを表現する方法が必要です。一つはUser -> ContactAction.user_id、もう一つは ですUser -> UserAction.user_id -> UserAction.user_actionable_id -> ContactAction.id。そして、named_scopes や finder でさらに処理するために、結果 (ContactActions) を 1 つのリストに結合します。

この関連付けは文字通り何十もの場所で必要になるため、すべてのケースに対してカスタム SQL を作成 (および維持!) するのは非常に面倒です。

私はこれを Rails で解決したいと考えていますが、他の提案 (たとえば、PostgreSQL 8.3 の手順または類似のもの) も受け付けています。最終的に重要なことは、Rails の便利な関数を他の関連付けと同じように使用できることです。さらに重要なことは、それらをネストすることもできます。

どんなアイデアでも大歓迎です。

ありがとうございました!


私自身の質問に一種の答えを提供するには:

おそらくデータベース ビューを使用してこれを解決し、必要に応じて適切な関連付けを追加します。上記の場合、私はできます

  • finder_sql の SQL を使用してビューを作成し、
  • 「contact_actions_or_requests」という名前を付けます。
  • SELECT 句を変更して user_id 列を追加し、
  • app/models/ContactActionsOrRequests.rb を追加し、
  • 次に、「has_many :contact_actions_or_requests」を user.rb に追加します。

レコードの更新をどのように処理するかはまだわかりません - これはビューでは不可能のようです - しかし、おそらくこれが最初のスタートです。

4

1 に答える 1

2

あなたが探している方法はマージです。r1 と r2 の 2 つの ActiveRecord::Relations がある場合、r1.merge(r2) を呼び出して、2 つを組み合わせた新しい ActiveRecord::Relation オブジェクトを取得できます。

これが機能するかどうかは、スコープの設定方法と、スコープを変更して意味のある結果を生成できるかどうかに大きく依存します。いくつかの例を見てみましょう:

Page モデルがあるとします。これには通常の created_at 属性と updated_at 属性があるため、次のようなスコープを持つことができます。

これをデータベースから引き出すと、次のようになります。

r1 = Page.updated # SELECT `pages`.* FROM `pages` WHERE (created_at != updated_at)
r2 = Page.not_updated # SELECT `pages`.* FROM `pages` WHERE (created_at = updated_at)
r1.merge(r2) # SELECT `pages`.* FROM `pages` WHERE (created_at != updated_at) AND (created_at = updated_at)
=> []

そのため、2 つの関係を結合しましたが、意味のある方法ではありませんでした。別のもの:

r1 = Page.where( :name => "Test1" ) # SELECT `pages`.* FROM `pages` WHERE `pages`.`name` = 'Test1'
r2 = Page.where( :name => "Test2" ) # SELECT `pages`.* FROM `pages` WHERE `pages`.`name` = 'Test2'
r1.merge(r2) # SELECT `pages`.* FROM `pages` WHERE `pages`.`name` = 'Test2'

したがって、状況によってはうまくいくかもしれませんが、うまくいかないかもしれません。

これを行う別の推奨される方法は、モデルに新しいスコープを作成することです。

class ContactAction < AR::Base
  belongs_to :user
  scope :pending, ...
  scope :active, ...
  scope :actions_and_requests, pending.active # Combine existing logic
  scope :actions_and_requests, -> { ... } # Or, write a new scope with custom logic
end

これは、収集したいさまざまな特性を 1 つのクエリで組み合わせたものです...

于 2013-01-08T09:41:50.683 に答える