Rails - 在关系模型中查找匹配项

时间:2014-07-01 13:17:03

标签: sql ruby-on-rails activerecord ruby-on-rails-4

假设我们有这两个模型:

class Attendee < ActiveRecord::Base
   has_many :dances
   has_many :partners, through: :events
end

class Dance < ActiveRecord::Base
   belongs_to :attendee
   belongs_to :partner, class_name: Attendee
end

我想实现一种方法,例如Dance.matches_of(attendee),只有当他的伙伴有一个他是合作伙伴的舞蹈时才会返回与会者的舞蹈。您将如何实施有效的解决方案?

编辑:

很抱歉,因为我无法很好地解释我的问题,我会尝试澄清它(我将Event班级名称更改为Dance)。如果用户想要与另一个人跳舞,他/她将创建一个对象Dance,指定合作伙伴。所以,让我们说Bob想和Sarah一起跳舞,数据库表dances看起来像这样(我会使用用户名而不是id来让它更清晰,希望如此):

|    id    |    attendee_id    |    partner_id    |
---------------------------------------------------
|    1     |       bob         |       sarah      |

所以,Dance.matches_of(bob)没有任何回报,因为没有人想和他跳舞,谁也想要他作为舞伴(可怜的鲍勃)。过了一会儿,莎拉认为鲍勃可能并不是一个坏人,他应该有机会发言。现在,dances表看起来像这样:

|    id    |    attendee_id    |    partner_id    |
---------------------------------------------------
|    1     |       bob         |       sarah      |
---------------------------------------------------
|    2     |      sarah        |        bob       |

Dance.matches_of(bob)现在返回id为1的舞蹈,因为这是显示Bob对与Sarah一起跳舞的兴趣的记录,并且Sarah也希望与他一起跳舞(Dance.matches_of(sarah)将检索第二条记录)。如果鲍勃也想与安娜一起跳舞,那么她也是如此,这个方法会找回两个记录,鲍勃将成为派对中最快乐的人,因为他有两个舞伴。

我希望这个解释更清楚,但我知道如果解释和理解起来很难,也许我所遵循的方法不正确,所以我愿意接受建议。

编辑2:

我提出的解决方案:

def self.matches_of(attendee) 
    attendee.dances.select { |dance| dance.partner.partners.include? attendee }
end

但我不认为它的效率会高得多。

3 个答案:

答案 0 :(得分:2)

根据您的模型,您可以向Dance模型添加matches_of范围:

class Attendee < ActiveRecord::Base
  has_many :dances
  has_many :partners, class_name: 'Attendee', through: :dances
end

class Dance < ActiveRecord::Base
  belongs_to :attendee
  belongs_to :partner, class_name: 'Attendee'

  scope :matches_of, -> (attendee) {
    where(partner_id: attendee.id, attendee_id: attendee.partner_ids)
  }
end

给出像

这样的舞蹈
|    id    |    attendee_id    |    partner_id    |
---------------------------------------------------
|    1     |       bob         |       sarah      |

matches_of将返回[]

bob = Attendee.find 1
Dance.matches_of(bob) 
# returns []

给出像

这样的舞蹈
|    id    |    attendee_id    |    partner_id    |
---------------------------------------------------
|    1     |       bob         |       sarah      |
---------------------------------------------------
|    2     |      sarah        |        bob       |

matches_of将返回Dance#2

Dance.matches_of(bob) 
# returns [#<Dance id: 2, attendee_id: 2, partner_id: 1>]

答案 1 :(得分:0)

如果partner_idid表中的attendees相关,我可以考虑这样的方法:

def partner_events
    Event.where('partner_id = ? and attendee_id in (?)', id, events.map(&:partner_id))
end

答案 2 :(得分:0)

def matches_of(attendee) 
  partner_ids = Event.pluck(:attendee_id).where(:partern_id = > attendee.id).uniq
  Event.where('attendee_id = ? and partner_id in (?)', attendee.id, partner_ids)
end