2012-01-15 1 views
1

J'ai un enregistrement actif Song modèle avec un champ songhash (chaîne (255)) qui contient un hachage Sha2. Lorsque je tente de trouver une chanson via rien de code suivant est renvoyée:Impossible de rechercher une chaîne longue dans ActiveRecord

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

Si je fais la même chose mais avec un « comme » QUERY cela fonctionne:

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 

Je crains qu'il a quelque chose à faire avec les encodages de chaînes, mais je ne sais pas pourquoi cette chaîne pourrait avoir des problèmes d'encodage: 61a9761b9ebd543b72c5ccf2ab6db198b067f7cf7f8412ee6e9c14b19611bc80

J'utilise les rails 3.1 avec sqlite db.

Des idées? Que se passe-t-il?

+0

Que fait 'Song.find_by_songhash (song.songhash)' de retour? – Gazler

+0

malheureusement, il retourne nul :-( – derhackler

+0

Comment générez-vous le hachage? Il n'y a pas d'espace présent dans le hachage est là?Avez-vous essayé d'utiliser le hachage directement, pas comme une variable? – Gazler

Répondre

0

Grâce à l'aide de @gazler et @basgys j'ai pu traquer le problème:

Il est en fait, un problème de codage provoqué par la fonction Digest :: Sha2 # hexdigest. Il renvoie une chaîne codée ASCII-8BIT. En le stockant dans la base de données, il semble être converti automatiquement en une chaîne UTF-8 (je vérifie cela en exécutant une requête select hex(songhash) from songs). Toutefois, lors de l'utilisation de la chaîne dans la requête, il ne semble pas effectuer cette conversion.

En interne ruby ​​semble gérer automatiquement les différentes conversions d'encodage. C'est pourquoi "abc"=="abc" bien qu'ils puissent avoir un codage différent.

Je suis sûr que ce comportement n'est pas attendu, mais je ne sais pas si c'est un bug - et si c'est un bug si c'est quelque part dans ActiveRecord, le pilote SQLite, ou SQLite lui-même.

Ma solution est maintenant d'ajouter un .encode("UTF-8") au résultat de la fonction de résumé.

0

Résumé

instructions SQL générées

# 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') 

Les énoncés suivants fonctionnent:

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

UPPER et COMME sont tous les deux sensibles à la casse

documentation SQLite

The LIKE operator does a pattern matching comparison. (A bug: SQLite only understands upper/lower case for ASCII characters by default. The LIKE operator is case sensitive by default for unicode characters that are beyond the ASCII range. For example, the expression 'a' LIKE 'A' is TRUE but 'æ' LIKE 'Æ' is FALSE.) See more

Pour investigage

  1. Charset égaux? (Rails - SQLite)
  2. chaîne stockée potentiellement sale (retours chariot, ...)
Questions connexes