如何使用 Arel 跨多态 has_one 关系进行查询

Posted

技术标签:

【中文标题】如何使用 Arel 跨多态 has_one 关系进行查询【英文标题】:How to use Arel to query across a polymorphic has_one relationship 【发布时间】:2020-07-16 03:15:00 【问题描述】:

我目前正在开发一个具有 jquery 数据表前端的项目,并且正在使用 ajax-datatables-rails gem 来处理后端。在查看了examples 之后,他们链接到并遇到了挑战。

我有一个数据表,它显示一个表中的数据,我们称之为 Foo,它与 3 个不同的表具有 has_one 多态关系。我的搜索需要搜索该多态关系中的列。

def my_filter
    ->(column,value)  Arel.sql("Foo.bar.description").matches("%#value%")
end

我尝试的一件事是转换 Arel::Table(a 是 arel 表)

Foo.where(a[:id].not_eq(nil)).find(
     :all,
     :joins => "bar",
     :conditions => ["bar.description LIKE %asd%", true]
 ).arel_table

但是在这种情况下,我收到一条消息,指出它在 Foo 上找不到 id。

【问题讨论】:

【参考方案1】:

我可以想到两种方法(根据您的 DBMS,幕后发生的事情可能几乎相同):

为所有不同多态 bar 类型的所有相关字段创建一个视图 加入动态创建的动态表

在这两种情况下,底层逻辑都是UNION 命令,看起来有点像以下:

SELECT foo_id, description FROM bars1
UNION
SELECT foo_id, description FROM bars2
UNION
SELECT foo_id, description FROM bars3

在视图的情况下,这个UNION 将构成视图本身的内容。

如果是动态表,它看起来像这样:

SELECT foos.*, bars.*
FROM foos
LEFT JOIN (
  SELECT foo_id, description FROM bars1
  UNION
  SELECT foo_id, description FROM bars2
  UNION
  SELECT foo_id, description FROM bars3
) AS bars ON bars.foo_id = foos.id
WHERE bars.description LIKE 'whatever%'

来看,Arel的使用和平时基本一样,只是你要明确JOIN

Foo.joins("LEFT JOIN bars ON bars.foo_id = foos.id").where("bars.description LIKE ?", description)

对于动态表,我确信有办法用纯 Arel 来表达它,但我个人会简单地使用 SQL:

joins_sql = <~SQL.strip_heredoc
  LEFT JOIN (
    SELECT foo_id, description FROM bars1
    UNION
    SELECT foo_id, description FROM bars2
    UNION
    SELECT foo_id, description FROM bars3
  ) AS bars ON bars.foo_id = foos.id
SQL

Foo.select("foos.*, bars.*").joins(joins_sql).where("bars.description LIKE ?", description)

希望对您有所帮助。

【讨论】:

【参考方案2】:

试试这个方法

class Foo < ActiveRecord::Base
  has_one :bar, polymorphic: true

  def view_columns
    @view_columns ||= 
      description:  source: "City.id", cond: by_description ,
    
  end

  def by_description
    ->(column)  joins(:bar).where("description LIKE ?", "%#column.search.value%")
  end
end

【讨论】:

以上是关于如何使用 Arel 跨多态 has_one 关系进行查询的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Arel(大概)创建一个不影响 Rails 3 中的查询的 ActiveRecord 范围?

从 has_many 更改为 has_one 关系轨

多个 has_one 和 has_many 关系

Rails 中具有相同键的两个表而不是 has_one 关系

Rails - has_one 关系:关联和非关联对象的范围

Arel:如何在 arel speak 中写 attr = NULL?