Подтвердить что ты не робот

Правильный способ избежать %% при создании запросов LIKE в Rails 3/ActiveRecord

Я хочу сопоставить поле url с префиксом url (который может содержать знаки процента), например. .where("url LIKE ?", "#{some_url}%"). Какой самый путь Rails?

4b9b3361

Ответ 1

Если я правильно понимаю, вы беспокоитесь о "%", появляющемся внутри some_url и правильно; вам также следует беспокоиться о встроенных подчеркиваниях ( "_" ), они являются LIKE-версией ".". в регулярном выражении. Я не думаю, что есть какой-то конкретный способ Rails, поэтому вы останетесь с gsub:

.where('url like ?', some_url.gsub('%', '\\\\\%').gsub('_', '\\\\\_') + '%')

Здесь нет необходимости в строковой интерполяции. Вам нужно удвоить обратную косую черту, чтобы избежать их значения из синтаксического анализатора базы данных, чтобы синтаксический анализатор LIKE увидел простой "\%" и знал, чтобы игнорировать знак с экранированным процентом.

Вы должны проверить свои журналы, чтобы убедиться, что пройдут две обратные косые черты. Я получаю запутывающие результаты от проверки вещей в irb, используя пять (!) Получает правильный вывод, но я не вижу смысла в нем; если кто-нибудь увидит смысл в пяти из них, будет оценен пояснительный комментарий.

ОБНОВЛЕНИЕ: Джейсон Кинг любезно предложил упрощение для кошмара беглых персонажей. Это позволяет указать временный escape-символ чтобы вы могли делать такие вещи:

.where("url LIKE ? ESCAPE '!'", some_url.gsub(/[!%_]/) { |x| '!' + x })

Я также переключился на блочную форму gsub, чтобы сделать ее менее неприятной.

Это стандартный синтаксис SQL92, поэтому он будет работать в любой базе данных, поддерживающей это, включая PostgreSQL, MySQL и SQLite.

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

Ответ 2

В Rails версии 4.2.x есть активный метод записи под названием sanitize_sql_like. Итак, вы можете сделать в своей модели область поиска, например:

scope :search, -> search { where('"accounts"."name" LIKE ?', "#{sanitize_sql_like(search)}%") }

и вызовите область как:

Account.search('Test_%')

Результирующая экранированная строка sql:

SELECT "accounts".* FROM "accounts" WHERE ("accounts"."name" LIKE 'Test\_\%%')

Подробнее здесь: http://edgeapi.rubyonrails.org/classes/ActiveRecord/Sanitization/ClassMethods.html

Ответ 3

https://gist.github.com/3656283

С помощью этого кода

Item.where(Item.arel_table[:name].matches("%sample!%code%"))

правильно escapes % между "sample" и "code" и соответствует "AAAsample% codeBBB", но не для "AAAsampleBBBcodeCCC" по умолчанию MySQL, PostgreSQL и SQLite3.

Ответ 4

Post.where('url like ?', "%#{some_url + '%'}%)