Я хочу сопоставить поле URL-адреса с префиксом URL-адреса (который может содержать знаки процента), например. .where("url LIKE ?", "#{some_url}%")
. Каков самый путь Rails?
правильный способ избежать %% при построении запросов LIKE в Rails 3/ActiveRecord
Ответы (4)
Если я правильно понимаю, вас беспокоит появление "%" внутри 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.
Встраивание одного языка в другой — это всегда кошмар, и с этим мало что можно поделать. Всегда будут уродливые маленькие кусочки, которые вам просто нужно усмехнуться и терпеть.
irb
, спасибо, что поймали это. Я предполагаю, что он проходит через три токена \\, \\ и \%, которые после обработки побега заканчиваются как \\% по желанию. Обычно я просто добавляю их, пока это не сработает, а затем реконструирую обоснование. Кто-нибудь знает оператор кавычек, который действительно выдает буквальные результаты без какой-либо обработки или большого беспорядка?
- person mu is too short; 19.04.2011
ESCAPE
, например: .where( "url LIKE ? ESCAPE '!'", some_url.gsub('%', '!%').gsub('_', '!_')
- person smathy; 19.04.2011
.where("url LIKE ? ESCAPE '!'", some_url.gsub(/([!%_])/, '!\1')
- person RecursivelyIronic; 12.09.2012
gsub
, двойное значение обратной косой черты может быть проблематичным, поэтому я обычно просто использую блочную форму при работе с непостоянной заменой, чтобы мне не приходилось беспокоиться о том, когда нужно использовать обратную косую черту. быть удвоены и когда они не делают. Но это всего лишь личные предпочтения.
- person mu is too short; 12.09.2012
Начиная с версии 4.2.x Rails существует активный метод записи с именем 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
ActiveRecord::Base.send(:sanitize_sql_like, "Test_%")
- person stwr667; 08.09.2020
https://gist.github.com/3656283
С этим кодом
Item.where(Item.arel_table[:name].matches("%sample!%code%"))
корректно экранирует %
между "sample" и "code" и соответствует "AAAsample%codeBBB", но не для "AAAsampleBBBcodeCCC" по крайней мере в MySQL, PostgreSQL и SQLite3.
Post.where('url like ?', "%#{some_url}%")
- person Rein Henrichs; 19.04.2011
%
или, по крайней мере, так я это читаю, то есть «который может содержать знаки процента»
- person thenengah; 19.04.2011
some_url
, не говоря уже о подчеркивании.
- person mu is too short; 19.04.2011
"%#{some_url + '%'}%
нет.
- person Rein Henrichs; 19.04.2011
%x%x%
от случайного "%#{a}%"
, когда a
просто оказывается неэкранированным 'x%x'
? В первом (преднамеренном) случае требуется что угодно x что угодно x что угодно, тогда как во втором случае требуется что угодно x%x < i>что угодно но получить что угодно x что угодно x что угодно, потому что никто не избежал этого. К тому времени, когда AR увидит аргумент LIKE, у него будет только строка со встроенным синтаксисом SQL, и уже слишком поздно делать выводы о намерениях программиста.
- person mu is too short; 19.04.2011
X%
для некоторого фиксированногоX
). Здесь есть некоторые примечания по этому поводу: stackoverflow.com/ вопросы/1566717/ - person mu is too short   schedule 19.04.2011%X%
, которые почти наверняка дадут вам сканирование таблицы. Извините, что у меня нет авторитетной ссылки, но вы, вероятно, могли бы составить план запроса и посмотреть, что произойдет. - person mu is too short   schedule 19.04.2011