提问人:bbharned 提问时间:9/7/2023 更新时间:9/8/2023 访问量:31
为什么 Heroku 附加数据库上的生产中的过滤搜索不起作用?
Why is Filterrific Search in Production on Heroku add-on db not working?
问:
我经常在我的 Rails 应用程序中使用 filterrific gem(当前为 5.2.3),并且喜欢它。我遇到了一个奇怪的问题。我有一个辅助的 Postgres 数据库供我的开发团队作为 Heroku 中的附加组件写入。我的过滤器设置适用于生产中的所有范围过滤器,但搜索返回错误。在开发中使用我的 SQL 种子数据,一切都可以完美运行。
型号.rb
filterrific(
default_filter_params: { },
available_filters: [
:sorted_by,
:with_search_please,
:with_manufacturer,
:with_boot_type,
:with_firm,
:with_monitor_count,
:with_ethernet_count,
],
)
scope :with_search_please, ->(search_string) {
return nil if search_string.blank?
terms = search_string.to_s.downcase.split(/\s+/)
terms = terms.map { |e|
#('%' + e + '%').gsub(/%+/, '%')
('%' + e.gsub('*', '%') + '%').gsub(/%+/, '%')
}
num_or_conds = 6
self.where(
terms.map { |term|
"(
LOWER(Terminals.Model) LIKE ?
OR LOWER(Terminals.TermcapModel) LIKE ?
OR LOWER(Manufacturers.Name) LIKE ?
OR LOWER(TerminalType.Type) LIKE ?
OR LOWER(Note.Description) LIKE ?
OR LOWER(FirmwarePackage.Version) LIKE ?
)"
}.join(' AND '),
*terms.map { |e| [e] * num_or_conds }.flatten
)
.joins(:Manufacturers).references(:ManufacturerIds)
.joins(:TerminalType).references(:TypeIds)
.includes(:Notes).references(:TerminalIds)
.joins(:FirmwarePackages).references(:TerminalFirmwarePackages)
}
日志错误
Completed 500 Internal Server Error in 15ms (ActiveRecord: 3.2ms | Allocations: 6057)
2023-09-07T12:56:11.955033+00:00 app[web.1]: F, [2023-09-07T12:56:11.954949 #2] FATAL -- : [9e6cf5c0-457c-47aa-9099-a5923e41b1ce]
2023-09-07T12:56:11.955035+00:00 app[web.1]: [9e6cf5c0-457c-47aa-9099-a5923e41b1ce] ActionView::Template::Error (PG::UndefinedTable: ERROR: missing FROM-clause entry for table "terminals"
2023-09-07T12:56:11.955035+00:00 app[web.1]: LINE 2: LOWER(Terminals.Model) LIKE '%a%'
2023-09-07T12:56:11.955036+00:00 app[web.1]: ^
我尝试了几种重写搜索查询、剥离条件甚至直接 SQL 查询的方法。这尤其困难,因为在开发中一切都可以完美运行,并且所有过滤范围在生产中都正常工作。我知道它一定与辅助附加数据库有关,因为我以前从未遇到过这种情况。
答:
您的问题是“terminals”表不是查询的一部分。
另请注意,Postgres 双引号标识符区分大小写,例如“Terminals”与“terminals”。
如果您发布整个查询以及有关定义此代码块的位置的一些上下文,我们也许能够提供帮助。
话虽如此,我还想借此机会帮助您清理一下该查询,因为它看起来很尴尬,IMO。
从帖子中可以看出,您的意图是查找:“搜索字符串中的每个单词都包含在以下列之一中的记录:Terminals.Model、Terminals.TermcapModel、Manufacturers.Name、TerminalType.Type、Note.Description、FirmwarePackage.Version”。
我们可以以更简单的方式实现这一点(并可能在此过程中解决您的问题),如下所示:
scope :with_search_please, ->(search_string) {
return none if search_string.blank? # A scope should not return nil
search_columns = [
Terminal.arel_table[:Model],
Terminal.arel_table[:TermcapModel],
Manufacturer.arel_table[:Name],
TerminalType.arel_table[:Type],
Note.arel_table[:Description],
FirmwarePackage.arel_table[:Version]
]
terms = search_string.to_s
.gsub("*","%")
.split
.map {|term| "%#{term}%"}
where(search_columns.map {|c| c.matches_any(terms)}.reduce(:and))
.joins(:Manufacturers)
.joins(:TerminalType)
.left_joins(:Notes)
.joins(:FirmwarePackages)
}
例如,如果search_string为“A Sun*ny Day”,则会产生类似于
(Terminals.Model ILIKE '%A%' OR Terminals.Model ILIKE '%Sun%ny%' OR Terminals.Model ILIKE '%Day%') AND
(Terminals.TermcapModel ILIKE '%A%' OR Terminals.TermcapModel ILIKE '%Sun%ny%' OR Terminals.TermcapModel ILIKE '%Day%') AND
(Manufacturers.Name ILIKE '%A%' OR Manufacturers.Name ILIKE '%Sun%ny%' OR Manufacturers.Name ILIKE '%Day%') AND
(TerminalType.Type ILIKE '%A%' OR TerminalType.Type ILIKE '%Sun%ny%' OR TerminalType.Type ILIKE '%Day%') AND
(Note.Description ILIKE '%A%' OR Note.Description ILIKE '%Sun%ny%' OR Note.Description ILIKE '%Day%') AND
(FirmwarePackage.Version ILIKE '%A%' OR FirmwarePackage.Version ILIKE '%Sun%ny%' OR FirmwarePackage.Version ILIKE '%Day%')
我们也可以通过全文搜索更进一步。
评论