Rails 审核搜索
Posted
技术标签:
【中文标题】Rails 审核搜索【英文标题】:Rails audited search 【发布时间】:2018-01-22 08:35:11 【问题描述】:我正在尝试查找去年设置为特定状态的所有项目。 我正在使用经过审计的 Rail 5,所以我创建了一个特定的审计模型,并尝试编写一个范围来返回我的条件:
Audit = Audited.audit_class
class Audit
scope :followupRebus, -> where(auditable_type: 'Followup')
.where(action: 'update')
.where("audited_changes LIKE '%step_id:[#Step::REBUS%'")
end
当我拿它并用.to_s
显示它时,postgres 中审核的文本字段的内容看起来像这样
"step_id"=>[9, 4], "active"=>[false, true]
如何使用 step_id = 9
进行所有审核?
编辑
非常感谢DRSE,我终于找到了一个可行的解决方案:
-
使用 DRSE 发送的迁移更改列的默认 TEXT 类型
像这样改变请求:
类审计 范围:followupRebus,-> where(auditable_type: 'Followup') .where(动作:'更新') .where("((audited_changes -> 'step_id')::json->>0)::int = :step_id", step_id: Step::REBUS)
结束
【问题讨论】:
你关心以前的版本或更新的版本是否有step_id = 9
?在您的示例中 "step_id"=>[9, 4]
这表明您的模型的先前版本具有 step_id = 9
因为 9
是数组中的第一个元素。
是的,它应该是 +,但它对我的需求至关重要
我在下面的回答中包含了所有案例。
【参考方案1】:
您需要使用Postgres JSON functions 查询JSON 列audited_changes 而不是LIKE 运算符。
要查找更改了 step_id
的审计,您可以使用
.where("(audited_changes -> 'step_id')::jsonb ? :step_id", step_id: '9')
注意使用named bind variable:step_id
,而不是使用活动记录问号 (?
) 替换,因为 Postgres 使用问号作为 JSON 查询运算符。
上述子句将找到step_id = 9
所在的任何审计,无论是在以前版本中设置的值还是在模型的更新版本中设置的值。
要查找以前版本中step_id = 9
的审计:
# Check if the first value (indexed by 0) in 'step_id' array is '9'
.where("(audited_changes -> 'step_id')::jsonb->0 ? :step_id", step_id: '9')
要查找在更新版本中设置了step_id = 9
的审计:
# Check if the second value (indexed by 1) in 'step_id' array is 9
.where("(audited_changes -> 'step_id')::jsonb->1 ? :step_id", step_id: '9')
(注意:您不应该直接对 where 子句的条件进行字符串插值,因为您将应用程序打开到 SQL injection vulnerability。请改用 rails style conditions with sanitized inputs。)
编辑
由于您已指示您的 audited_changes 列类型是 TEXT 而不是 JSON 类型,您将需要运行迁移以更改列类型或在查询中转换列。
要在查询执行时将列转换为 JSON,请使用 audited_changes::json
,因此示例如下:
.where("(audited_changes::json -> 'step_id')::json ? :step_id", step_id: '9')
要将列更改为 JSON,请以 rails g migration ChangeAuditedChangesColumnToJSONB
开头。然后在您的迁移文件 (db/migrate/timestamp_change_audited_changes_column_to_jsonb.rb
) 中写入:
class ChangeAuditedChangesColumnToJSONB < ActiveRecord::Migration[5.1]
def up
change_column :audits, :audited_changes, :jsonb, using: 'audited_changes::JSONB'
end
def down
change_column :audits, :audited_changes, :text
end
end
然后运行rails db:migrate
,您应该一切顺利。
对于使用 Audited 的新项目,您可以add a param to the install step 为 audited_changes 列指定使用 JSON 或 JSONB 类型。
rails generate audited:install --audited-changes-column-type jsonb # or json
【讨论】:
感谢您的反应和回答的质量。 没问题。如果它为您解决了问题,请将其标记为已接受的答案。谢谢。 我尝试了您的解决方案,但是已审核 gem 的 audited_changes 是在 TEXT 中输入的,所以我得到以下错误 operator does not exist: text -> unknown 注意我在 postgres 9.6 你知道怎么做吗投射它? @Jaycreation 请查看我的更新答案,其中包含有关如何将列类型从 TEXT 更改为 JSONB 的说明。 谢谢,但看起来 audited 使用的语法对 json 不友好,转换后出现错误:令牌“-”无效。就像我试图将文本投射到 jon 时一样以上是关于Rails 审核搜索的主要内容,如果未能解决你的问题,请参考以下文章
ActionController::InvalidAuthenticityToken Rails 5 / 设计 / 审核 / PaperTrail gem
使用 rails audited gem 根据已审核的更改过滤掉结果