根据使用同一表格的多个关联的条件选择记录

时间:2018-10-31 17:50:44

标签: ruby-on-rails ruby-on-rails-4 associations

我在Rails中实际上是一种常见情况,在该情况下,我有一个具有两个关联的模型。我希望能够基于其中一个或两个关联的条件来搜索模型定义的特定记录。

不同之处在于,这两个关联使用同一张表。

这是主要型号:

class Resource < ActiveRecord::Base
  belongs_to :primary_item, class_name: 'Item', foreign_key: 'primary_item_Id'
  belongs_to :secondary_item, class_name: 'Item', foreign_key: 'secondary_item_Id'
  ...

还有Item模型:

class Item < ActiveRecord::Base
  has_many :res_primary, class_name: 'Resource', foreign_key: 'primary_item_Id'
  has_many :res_secondary, class_name: 'Resource', foreign_key: 'secondary_item_Id'
  ...

让我们假设Item有一个名为name的字符串字段。这只是物品的名称。我希望能够找到具有像给定名称这样的主要和/或次要项目的所有资源。如果我只是在过滤主要项目,则如下所示(我认为):

@resources.joins(:primary_item)
          .where("#{Item.table_name}.name like #{primary_search_string}")

primary_search_string只是我想在name中匹配的字符串。这很好。类似的搜索可用于次要项目。

现在假设我希望用户能够搜索具有给定主要项目名称,给定次要名称(按名称)或两者兼有的资源(每个都有其自己的名称)。我将有一个具有独立值的primary_search_stringsecondary_search_string。其中之一可能是nil,这意味着我不想基于该字符串来缩小搜索范围。我想要的是根据两个字符串之一或两个来过滤资源,具体取决于它们是否为nil。这是我最终可以使用的东西,但看起来很尴尬:

@resources = <some query that obtains an active record relation of resources>

if primary_search_string then
  @resources = @resources.joins(:primary_item)
                         .where("#{Item.table_name}.name like #{primary_search_string}")
  if secondary_search_string then
    @resources = @resources.joins(:secondary_item)
                           .where("secondary_items_#{Item.table_name}.name like #{secondary_search_string}")
  end
elsif secondary_search_string then
  @resources = @resources.joins(:secondary_item)
                        .where("#{Item.table_name}.name like #{secondary_search_string}")
end

请注意,如果我仅联接一个表,怎么用Item.table_name知道表的名称。但是,如果必须同时连接两个表,则Rails必须通过进一步指定关联名称secondary_items_#{Item.table_name}来区分表的第二个实例。

我的问题是,是否有一种更简单的处理方法,而不必涉及在where子句中引用关联的表名?由于我要引用关联的表名,并且表名可能会有所不同,具体取决于我要加入其中一个还是两个都加入,因此最终检查了nil的搜索字符串,这是一个确定我是否要多次加入Item表的方法。在这个特定的程序示例中,我可以检查它并保持它的笨拙。但是,如果我不知道@resources之前是否已加入主要项目,又想根据次要项目进行过滤,该怎么办?在那种情况下,我不知道在where子句中将使用什么关联表名称,因为我不知道它是否已经join被编辑。

我怀疑这里可能有更好的方法,这是我问题的本质。

1 个答案:

答案 0 :(得分:0)

如果您有两个单独的关联,但是它们都属于同一类型的子对象(例如,资源),那么除了联接/包含之外,您可以专注于查找与其中一个匹配的Resource记录您想要的父记录primary_item_id的{​​{1}}或secondary_item_id

Rails 3/4本身并不支持OR查询,但是一种蛮力的方式是通过找到属于Item的{​​{1}}的ID作为主要或次要关联。 (这显然效率低下,因为您正在执行多个数据库查询。)

Resources

Rails 5支持“或”查询,因此更加简单:

Item