Я хочу сопоставить поле url с префиксом url (который может содержать знаки процента), например. .where("url LIKE ?", "#{some_url}%")
.
Какой самый путь Rails?
Правильный способ избежать %% при создании запросов LIKE в Rails 3/ActiveRecord
Ответ 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 + '%'}%)