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 审核搜索的主要内容,如果未能解决你的问题,请参考以下文章

经审核的 Rails 批量创建

ActionController::InvalidAuthenticityToken Rails 5 / 设计 / 审核 / PaperTrail gem

使用 rails audited gem 根据已审核的更改过滤掉结果

使用 Audited gem 在 Rails 5.2 应用程序中在哪里列出未审核的列?

不适用于经过审核的 4.7 gem 更新模型

text 审核结果报告RegEx搜索