本文介绍了Ruby on Rails的3:合并多个的has_many或has_many_through协会结果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下的车型。用户有UserActions,和一个可能UserAction可以是ContactAction(UserAction是一个多态性)。有喜欢的LoginAction等于是

I have the following models. Users have UserActions, and one possible UserAction can be a ContactAction (UserAction is a polymorphism). There are other actions like LoginAction etc. So


 class 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
 end

class UserAction < AR::Base
 belongs_to :user
 belongs_to :user_actionable, :polymorphic => true
end

class ContactAction < AR::Base
 belongs_to :user
 named_scope :pending, ...
 named_scope :active, ...
end

的想法是,一​​个ContactAction连接两个用户(与其它后果在应用内),并总是具有接收和发送端。与此同时,一个ContactAction可以有不同的状态,例如过期,等待等。

The idea is that a ContactAction joins two users (with other consequences within the app) and always has a receiving and a sending end. At the same time, a ContactAction can have different states, e.g. expired, pending, etc.

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

I can say @user.contact_actions.pending or @user.contact_requests.expired to list all pending / expired requests a user has sent or received. This works fine.

我现在想一个办法的加入这两种类型的ContactAction的。即 @ user.contact_actions_or_requests 。我试过如下:

What I would now like is a way to join both types of ContactAction. I.e. @user.contact_actions_or_requests. I tried the following:


class User

 def contact_actions_or_requests
  self.contact_actions + self.contact_requests
 end

 # or
 has_many :contact_actions_or_requests, :finder_sql => ..., :counter_sql => ...

end

,但所有这些都认为是不可能使用额外的发现者或named_scopes上的关联,例如顶部的问题 @ user.contact_actions_or_requests.find(...) @ user.contact_actions_or_requests.expired

基本上,我需要一种方法来恩preSS 1:n的协会,有两种不同的路径。一个是用户 - > ContactAction.user_id ,另一个是用户 - > UserAction.user_id - > UserAction.user_actionable_id - > ContactAction.id 。然后加入一个单一的列表的结果(ContactActions)与named_scopes和/或发现者进一步处理。

Basically, I need a way to express a 1:n association which has two different paths. One is User -> ContactAction.user_id, the other is User -> UserAction.user_id -> UserAction.user_actionable_id -> ContactAction.id. And then join the results (ContactActions) in one single list for further processing with named_scopes and/or finders.

因为我需要这个协会在字面上几十个地方,这将是写一个大麻烦(和维护!),每案自定义的SQL。

Since I need this association in literally dozens of places, it would be a major hassle to write (and maintain!) custom SQL for every case.

我想preFER在Rails中解决这个问题,但我也开放给其他建议(例如一个PostgreSQL 8.3的程序或某事这类似于)。重要的是,在年底,我可以使用的Rails的便利功能,如与其他任何联系,更重要的是,还巢他们。

I would prefer to solve this in Rails, but I am also open to other suggestions (e.g. a PostgreSQL 8.3 procedure or something simliar). The important thing is that in the end, I can use Rails's convenience functions like with any other association, and more importantly, also nest them.

任何想法将非常AP preciated。

Any ideas would be very much appreciated.

感谢您!

要以我自己的问题提供一个答案排序的:

To provide a sort-of answer to my own question:

我可能会解决这个使用数据库视图,并根据需要添加相应的关联。针对上述情况,我可以

I will probably solve this using a database view and add appropriate associations as needed. For the above, I can


  • 使用SQL在finder_sql创建视图,

  • 将其命名为contact_actions_or_requests,

  • 修改SELECT子句中添加user_id列,

  • 添加应用程序/模型/ ContactActionsOrRequests.rb,

  • ,然后添加的has_many:contact_actions_or_requests来user.rb

我不知道我怎么会处理更新记录,但 - 这似乎并不可能,以期 - 但也许这是第一启动

I don't know how I'll handle updating records yet - this seems not to be possible with a view - but maybe this is a first start.

推荐答案

您正在寻找的方法是合并。如果你有两个的ActiveRecord ::关系,R1和R2,可以调用r1.merge(R2)来获得,它结合了两个新的ActiveRecord ::关系的对象。

The method you are looking for is merge. If you have two ActiveRecord::Relations, r1 and r2, you can call r1.merge(r2) to get a new ActiveRecord::Relation object that combines the two.

如果这会为你工作在你的范围如何设置在很大程度上取决于,如果你可以改变他们产生有意义的结果。让我们看几个例子:

If this will work for you depends largely on how your scopes are set up and if you can change them to produce a meaningful result. Let's look at a few examples:

假设你有一个页面模型。它有正常的created_at和属性的updated_at,所以我们可以有这样的范围:
:更新 - > {其中('!created_at =的updated_at')}
:not_updated - > {其中('created_at =的updated_at')}

Suppose you have a Page model. It has the normal created_at and updated_at attributes, so we could have scopes like::updated -> { where('created_at != updated_at') }:not_updated -> { where('created_at = updated_at') }

如果你拉这从数据库中,你会得到:

If you pull this out of the database you'll get:

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)
=> []

因此​​它没有将两者结合起来的关系,但不能以有意义的方式。另一个问题:

So it did combine the two relations, but not in a meaningful way. Another one:

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'

因此​​,它可能为你工作,但也许不是,根据您的情况。

So, it might work for you, but maybe not, depending on your situation.

另外,同时建议,这样做的方法是创建您模型的新范围:

Another, and recommended, way of doing this is to create a new scope on you model:

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

,结合你想在一个查询收集不同的特质......

That combines the different traits you want to collect in one query ...

这篇关于Ruby on Rails的3:合并多个的has_many或has_many_through协会结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-10 22:08