我有以下型号。用户具有UserActions,一个可能的UserAction可以是ContactAction(UserAction是一种多态性)。还有其他 Action ,例如LoginAction等。

类User has_many:contact_requests,:class_name =>“ContactAction”
has_many:user_actions
has_many_polymorphs:user_actionables,:from => [:contact_actions,...],:through =>:user_actions
结尾

类UserAction 当属:用户
归属于:user_actionable,:polymorphic => true
结尾

类ContactAction 当属:用户
named_scope:待处理...
named_scope: Activity 中,...
结尾

这个想法是一个ContactAction加入了两个用户(在应用程序内带来其他后果),并且始终具有接收端和发送端。同时,ContactAction可以具有不同的状态,例如过期,待处理等

我可以说@user.contact_actions.pending@user.contact_requests.expired列出用户已发送或接收的所有未决/过期请求。这很好。

我现在想要的是一种加入两种类型的ContactAction的方法。 IE。 @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 => ...

结尾

但所有这些都有一个问题,即无法在关联之上使用其他查找器或named_scopes,例如@user.contact_actions_or_requests.find(...)@user.contact_actions_or_requests.expired

基本上,我需要一种表示具有两种不同路径的1:n关联的方法。一个是User -> ContactAction.user_id,另一个是User -> UserAction.user_id -> UserAction.user_actionable_id -> ContactAction.id。然后将结果(ContactActions)合并到一个列表中,以便使用named_scopes和/或finders进行进一步处理。

由于我实际上需要在数十个地方建立这种关联,因此为每种情况编写(并维护!)自定义SQL将会是一大麻烦。

我更愿意在Rails中解决此问题,但是我也愿意接受其他建议(例如PostgreSQL 8.3过程或类似的东西)。重要的是,最后,我可以像使用任何其他关联一样使用Rails的便捷功能,更重要的是,还可以嵌套它们。

任何想法将不胜感激。

谢谢!

为我自己的问题提供某种答案:

我可能会使用数据库 View 解决此问题,并根据需要添加适当的关联。对于以上内容,我可以

  • 使用finder_sql中的SQL创建 View
  • 将其命名为“contact_actions_or_requests”,
  • 修改SELECT子句以添加user_id列
  • 添加一个应用程序/模型/ContactActionsOrRequests.rb,
  • ,然后将“has_many:contact_actions_or_requests”添加到user.rb。

  • 我尚不知道如何处理更新记录-用 View 看来这是不可能的-但这也许是第一次。

    最佳答案

    您正在寻找的方法是合并。如果您有两个ActiveRecord::Relations,r1和r2,则可以调用r1.merge(r2)来获得一个新的ActiveRecord::Relation对象,该对象将两者结合在一起。

    对于您而言,这是否奏效很大程度上取决于范围的设置方式以及是否可以对其进行更改以产生有意义的结果。让我们看几个例子:

    假设您有一个Page模型。它具有常规的created_at和updated_at属性,因此我们可以使用如下范围:
    :updated-> {where('created_at!= Updated_at')}
    :not_updated-> {其中('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)
    => []
    

    因此,它确实结合了这两种关系,但没有有意义的方式。另一个:
    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
    

    这结合了您要在一个查询中收集的不同特征...

    10-01 17:01