Ransack gem - поиск без учета регистра

Используя гем Ransack, я хочу сделать так

https://github.com/activerecord-hackery/ransack/wiki/Basic-Searching#i_cont-work-in-progress-dont-use-yet

 >> User.search(first_name_i_cont: 'Rya').result.to_sql
=> SELECT "users".* FROM "users"  WHERE (UPPER("users"."first_name") LIKE UPPER('%Rya%'))

но этот метод еще не работает.

поэтому я попытался выяснить, есть ли другой способ сделать это, я получил некоторую информацию о том, как это сделать

//in model

  ransacker :ig_case, formatter: proc { |v| v.mb_chars.upcase.to_s } do |parent|
    Arel::Nodes::NamedFunction.new('UPPER',[parent.table[:firstname]])
  end

//in config/ranrack.rb

Ransack.configure do |config|
  config.add_predicate 'ig_case', # Name your predicate
    arel_predicate: 'matches',
    formatter: proc { |v| "%#{v.to_s.gsub(/([\\|\%|.])/, '\\\\\\1').mb_chars.upcase}%"},
    validator: proc { |v| v.present? },
    compounds: true,
    type: :string
end

   // use way
User.search({ firstname_or_lastname_ig_case: "ABC"}).result.to_sql

=> "SELECT `Users`.* FROM `Users` WHERE ((UPPER(`users`.`firstname`) LIKE '%ABC%' OR (`users`.`lastname`) LIKE '%ABC%'))"

через несколько часов я обнаружил, что могу получить одно поле в верхнем регистре каждый раз, когда использовал модельный способ.

Я могу преобразовать все поле, если выберу способ конфигурации, но я не могу получить sql, подобный этому 'UPPER ("users". "first_name")'

Есть ли решение? Я действительно очень благодарен.


person Azi Chen    schedule 17.09.2014    source источник


Ответы (1)


Вам нужно будет переопределить Arel в адаптерах, выполнив следующие действия:

    module Arel

      module Nodes
        %w{
          IDoesNotMatch
          IMatches
        }.each do |name|
          const_set name, Class.new(Binary)
        end
      end

      module Predications
        def i_matches other
          Nodes::IMatches.new self, other
        end

        def i_does_not_match other
          Nodes::IDoesNotMatch.new self, other
        end
      end

      module Visitors

        class ToSql < Arel::Visitors::Visitor
          def visit_Arel_Nodes_IDoesNotMatch o
            "UPPER(#{visit o.left}) NOT LIKE UPPER(#{visit o.right})"
          end

          def visit_Arel_Nodes_IMatches o
            "UPPER(#{visit o.left}) LIKE UPPER(#{visit o.right})"
          end
        end

        class Dot < Arel::Visitors::Visitor
          alias :visit_Arel_Nodes_IMatches            :binary
          alias :visit_Arel_Nodes_IDoesNotMatch       :binary
        end

        class DepthFirst < Visitor

          unless method_defined?(:visit_Arel_Nodes_InfixOperation)
            alias :visit_Arel_Nodes_InfixOperation :binary
            alias :visit_Arel_Nodes_IMatches            :binary
            alias :visit_Arel_Nodes_IDoesNotMatch       :binary
          end

        end

      end
    end

В дополнение к этому вам нужно будет предоставить методы для предикатов.

Вот моя вилка драгоценного камня, который решает вашу проблему: https://github.com/Kartstig/ransack

У меня есть PR, который был закрыт, потому что он мог нарушить работу других адаптеров. До сих пор он отлично работал в моем приложении: https://github.com/activerecord-hackery/ransack/pull/405

Также обратите внимание, что если у вас есть индексированные столбцы, они будут проигнорированы, поскольку вы используете UPPER.

person Zoidberg    schedule 17.09.2014
comment
Потрясающий! Рад помочь. Не могли бы вы отметить это как ответ? - person Zoidberg; 17.09.2014