在ActiveRecord上遍历HABTM关系

时间:2020-03-06 15:00:34  来源:igfitidea点击:

我正在为我的学校在Rails上开发一个项目(不用担心这不会在代码上评分),并且我正在寻找一种干净的方法来遍历ActiveRecord中的关系。

我有一个称为用户,组和分配的ActiveRecord类。用户和组以及组和分配具有HABTM关系。现在,我需要的是一个用户函数get_group(aid),其中"给了一个用户,找到分配了任务的组"。

简单的路线是:

def get_group(aid)
    group = nil
    groups.each { |g| group = g if g.assignment.find(aid).id == aid }
    return group
  end

是否有一种更清洁的实现方式可以利用组和分配之间的HABTM关系,而不仅仅是迭代?我还尝试过的一件事是find()的:include选项,如下所示:

def get_group(aid)
   user.groups.find(:first, 
     :include => :assignments, 
     :conditions => ["assignments.id = ?", aid])
  end

但这似乎不起作用。有任何想法吗?

解决方案

首先,要小心。由于我们在两种关系中都使用了" has_and_belongs_to_many",因此对于给定的"用户"和"分配",可能会有多个"组"。因此,我将实现一个返回" Group"数组的方法。

其次,采用赋值ID的方法User#get_group的名称极具误导性,且不像Ruby。

这是使用交集运算符Ruby的" Array#&"获取所有公共组的一种干净方法。由于该方法返回的是Group实例,因此我给该方法起了一个更显眼的名称,并将其放在Group上。但是请注意,它会加载与一个人相关但与另一个不相关的Group

class Group < ActiveRecord::Base
  has_and_belongs_to_many :assignments
  has_and_belongs_to_many :users

  # Use the array intersection operator to find all groups associated with both the User and Assignment 
  # instances that were passed in
  def self.find_all_by_user_and_assignment(user, assignment)
    user.groups & assignment.groups
  end
end

然后,如果我们确实需要User#get_groups方法,则可以这样定义:

class User < ActiveRecord::Base
  has_and_belongs_to_many :groups

  def get_groups(assignment_id)
    Group.find_all_by_user_and_assignment(self, Assignment.find(assignment_id))
  end
end

尽管我可能将其命名为User#groups_by_assignment_id

我的"分配"模型很简单:

class Assignment < ActiveRecord::Base
  has_and_belongs_to_many :groups
end