Rails 6 Ransack i PG Array

Witam,
Mam problem z wyszukiwanie w Ransack w kolumnie Postgresql Array.
Pole zawiera dane zapisane w taki sposób np: [3, 1, 2]
Przeszukując internet znalazłem to ruby on rails - How to search array through ransack gem? - Stack Overflow
Po stworzeniu pliku arel.rb w katalogu initializers
require ‘arel/nodes/binary’
require ‘arel/predications’
require ‘arel/visitors/postgresql’

module Arel
  class Nodes::ContainsArray < Arel::Nodes::Binary
    def operator
      :"@>"
    end
  end

  class Visitors::PostgreSQL
    private

    def visit_Arel_Nodes_ContainsArray(o, collector)
      infix_value o, collector, ' @> '
    end
  end

  module Predications
    def contains(other)
      Nodes::ContainsArray.new self, Nodes.build_quoted(other, self)
    end
  end
end

Dodałem także plik ransack.rb który zawiera:

Ransack.configure do |config|
  config.add_predicate 'contains',
                       arel_predicate: 'contains',
                       formatter: proc { |v| "{#{v}}" },
                       validator: proc { |v| v.present? },
                       type: :string
end

To pozwoliło na stworzenie wyszukiwarki w polu array.
<%= f.search_field :exaple_of_something_contains %>

Jeśli w input wpiszę 1,2 - lub kombinację numerów które mogą znaleźć się w tabeli działa poprawnie.
Problem pojawia się jeśli np chciałbym wykorzystać check_box multi select.

          <% Profile.exaple_of_something.each do |key, value| %>
              <li>
                <%= f.check_box :exaple_of_something_contains,{:multiple => true}, value, nil %>
                <%= h key -%>
              </li>
          <% end %>

wtedy w params dostaję array i otrzymuję błąd: Invalid query parameters: expected Array (got String) for param
Próba zmiany ransack.rb w formatter na

formatter: proc { |v| "{#{v}.join(", "}" },

Dalej otrzymuje ten sam błąd Invalid query paremeters. Czy ma ktoś z Was pomysł jak to rozwiązać?
Tutaj przykładowe repo

1 Like

Zmodyfikowałem arel.rb
require ‘arel/nodes/binary’
require ‘arel/predications’
require ‘arel/visitors/postgresql’

module Arel
  class Nodes::ContainsArray < Arel::Nodes::Binary
    def operator
      :"@>"
    end
  end

  class Nodes::ContainsString < Arel::Nodes::Binary
    def operator
      :"@>"
    end
  end

  class Visitors::PostgreSQL
    private

    def visit_Arel_Nodes_ContainsArray(o, collector)
      infix_value o, collector, ' @> '
    end

    def visit_Arel_Nodes_ContainsString(o, collector)
      infix_value o, collector, ' @> '
    end
  end

  module Predications
    def contains(other)
      Nodes::ContainsArray.new self, Nodes.build_quoted(other, self)
    end

    def contains_string(other)
      Nodes::ContainsString.new self, Nodes.build_quoted(other, self)
    end
  end
end

Dodałem także wpis w ransack.rb

  config.add_predicate 'contains_string',
                       arel_predicate: 'contains_string',
                       formatter: proc { |v| "{#{v.delete(']').delete('[')}}" },
                       validator: proc { |v| v.present? },
                       type: :string

Teraz działa

1 Like