Не удается запросить длинную строку в ActiveRecord - PullRequest
1 голос
/ 16 января 2012

У меня есть модель активной записи Song с полем songhash (строка (255)), которая содержит хэш Sha2.Когда я пытаюсь найти песню по следующему коду, ничего не возвращается:

song = Song.all.first
song2 = Song.where(songhash: song.songhash).first
# song is a valid object with a songhash set, but song2 is nil!

Если я делаю то же самое с запросом «Мне нравится», это работает:

song = Song.all.first
song2 = Song.where("songhash like ?", song.songhash).first
# song2 is a valid object now
song2.songhash == song.songhash
# the equation is true

Iбоюсь, что это как-то связано со строковым кодированием, но я понятия не имею, почему эта строка может иметь проблемы с кодировкой: 61a9761b9ebd543b72c5ccf2ab6db198b067f7cf7f8412ee6e9c14b19611bc80

Я использую rails 3.1 с sqlite db.

Любые идеичто происходит?

Ответы [ 2 ]

0 голосов
/ 19 января 2012

Благодаря помощи @gazler и @basgys мне удалось отследить проблему:

На самом деле это проблема кодирования, вызванная функцией Digest :: Sha2 # hexdigest.Возвращает строку, которая закодирована как ASCII-8BIT.При сохранении этого в базе данных, он, кажется, автоматически конвертируется в строку UTF-8 (я проверяю это, выполняя запрос select hex(songhash) from songs).Однако при использовании строки в запросе это преобразование не выполняется.

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

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

Теперь я могу добавить .encode("UTF-8") к результату функции дайджеста.

0 голосов
/ 16 января 2012

Сводка

Сгенерированные операторы SQL

 # With = / It doesn't work
 SELECT "songs".* FROM "songs" WHERE "songs"."type" 
 IN ('PlaylistSong') AND "songs"."songhash" =
 '61a9761b9ebd543b72c5ccf2ab6db198b067f7cf7f8412ee6e9c14b19611bc80'

 # With like / It works
 SELECT "songs".* FROM "songs" WHERE "songs"."type" 
 IN ('PlaylistSong') AND (songhash like 
 '61a9761b9ebd543b72c5ccf2ab6db198b067f7cf7f8412ee6e9c14b19611bc80')

 # With upper / It works
 SELECT "songs".* FROM "songs" WHERE "songs"."type" 
 IN ('PlaylistSong') AND (UPPER(songhash) = 
 '61A9761B9EBD543B72C5CCF2AB6DB198B067F7CF7F8412EE6E9C14B19611BC80')

Работают следующие операторы:

 Song.where(['UPPER(songhash) = ?', song.songhash.upcase]).first
 Song.where(['songhash like ?', song.songhash]).first

UPPER и LIKE не чувствительны к регистру

документация SQLite

Оператор LIKE выполняет сравнение сопоставления с образцом.(Ошибка: SQLite понимает только прописные / строчные буквы для символов ASCII по умолчанию. Оператор LIKE по умолчанию чувствителен к регистру символов Unicode, которые превышают диапазона ASCII. Например, выражение 'a' LIKE«А» - ИСТИНА, но «L», КАК «F», ЛОЖЬ.) Подробнее

Для расследования

  1. Charset равняется?(Rails - SQLite)
  2. Строка хранится потенциально грязно (возврат каретки, ...)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...