簡體   English   中英

Rails ransack和paper_trail在postgresql json列中搜索密鑰

[英]Rails ransack and paper_trail search for a key in a postgresql json column

我正在使用Ruby on Rails創建我的網站。 我正在使用paper_trail gem保存模型的歷史更改,並使用ransack gem執行搜索表單。 一切正常,但是,我想創建一個搜索表單來過濾對模型所做的更改。

這是要在erb中過濾的代碼框架:

  <%= search_form_for [@q, @q_deleted], url: ticket_index_path, class: 'form-inline' do |f| %>
    <div class="row">
      <div class="col-sm-6 col-lg-4">
        <%= f.label :versions_whodunnit_eq, t('audit.view.text.user').capitalize, {class: "control-label"} %>
        <%= f.select :versions_whodunnit_eq, User.all.collect { |p| [p.name, p.id] }, {include_blank: true}, {class: 'form-control input-sm'} %>
      </div>
      <div class="col-sm-6 col-lg-4">
        <%= f.label :versions_event_eq, t('audit.view.text.event').capitalize, {class: "control-label"} %>
        <%= f.select :versions_event_eq, {t('common.versions_event.create') => 'create', t('common.versions_event.update') => 'update', t('common.versions_event.destroy') => 'destroy'}, {include_blank: true}, {class: 'form-control input-sm'}  %>
      </div>
      <div class="col-sm-6 col-lg-4">
        <%= f.label :versions_object_changes_eq, t('audit.view.text.change').capitalize, {class: "control-label"} %>
        <%= f.select :versions_object_changes_eq, Audit::TicketsController::COLUMNS.collect { |column| [t("audit.view.text.column_change.#{column}"), column] }, {include_blank: true}, {class: 'form-control input-sm'} %>
      </div>
    </div>
    <div class="row">
      <div class="col-sm-6 col-lg-3">
        <br>
        <%= f.submit 'Buscar', class: 'btn btn-primary' %>
        <%= link_to 'Limpiar', request.path, class: 'btn btn-default cancel-button' %>
      </div>
    </div>
  <% end %>

並進入視圖控制器:

params[:q] ||= {}

params[:page] = 1 if params[:page].blank?
params[:page_deleted] = 1 if params[:page_deleted].blank?

@q = Ticket.all.order(date: :desc).ransack(params[:q])
@q_deleted = Ticket.only_deleted.order(date: :desc).ransack(params[:q])

result = @q.result(distinct: true)
result_deleted = @q_deleted.result(distinct: true)

@active_count = result.count
@deleted_count = result_deleted.count

@tickets = result.paginate(page: params[:page], per_page: params[:per_page])
@tickets_deleted = result_deleted.paginate(page: params[:page_deleted], per_page: params[:per_page])

問題是,當我通過:versions_object_changes_eq進行過濾時,PostgreSQL引發了一個可以比較json列的錯誤:

SELECT DISTINCT "tickets".* FROM "tickets" LEFT OUTER JOIN "versions" ON "versions"."item_id" = "tickets"."id" AND "versions"."item_type" = 'Ticket' WHERE "tickets"."deleted_at" IS NULL AND "versions"."object_changes" = 'date' ORDER BY "tickets"."date" DESC

該SQL的問題在於訪問json鍵的方式是->>,然后正確的方法是:

SELECT DISTINCT "tickets".* FROM "tickets" LEFT OUTER JOIN "versions" ON "versions"."item_id" = "tickets"."id" AND "versions"."item_type" = 'Ticket' WHERE "tickets"."deleted_at" IS NULL AND ("versions"."object_changes"->>'ticket_state' IS NOT NULL) ORDER BY "tickets"."date" DESC

我該怎么做?

..當我通過:versions_object_changes_eq過濾時[我得到此SQL]

 where "versions"."object_changes" = 'date' 

[但我想要:]

 where "versions"."object_changes"->>'ticket_state' IS NOT NULL 

我不認為ransack支持->>運算符。 您可以嘗試編寫自定義ransacker ,但是它們的文檔記錄不充分,因此不建議這樣做。

PaperTrail確實支持->>運算符。 使用PaperTrail::Version.where_object 但是,這可能很難與Ticket.ransack結合使用。

您可以嘗試以下三件事:

  1. 使用ActiveRecord的merge方法合並Ticket.ransackVersion.where_object
  2. 進行兩個單獨的查詢,並取其結果的交集
  3. 有條件地將所需的確切原始SQL添加到Relation

我遇到了像您這樣的問題,並通過添加以下內容解決了該問題:

ransacker :ticket_state do |parent|
  Arel::Nodes::InfixOperation.new('->>', parent.table[:object_changes], Arel::Nodes.build_quoted('ticket_state'))
end

對我的模特。 然后,您可以在ticket_state上使用任何Ransack謂詞,例如:

Ticket.ticket_state_not_null

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM