2011-09-15 88 views
2

使用Rails 3.1和sqlite3進行開發,測試環境。sqlite3 varchar匹配「like」但不匹配「=」

增加了一個新的表中遷移:

create_table :api_keys do |t| 
    t.string :api_key 
    t.integer :user_id 
    t.timestamps 
end 

這將產生一個表,下面的模式:

create_table "api_keys", :force => true do |t| 
    t.string "api_key" 
    t.integer "user_id" 
    t.datetime "created_at" 
    t.datetime "updated_at" 
end 

在ActiveRecord的模式:

before_create :fill_api_key 

private 

def fill_api_key 
    self.api_key = SecureRandom.hex(30) 
end 

的ActiveRecord的動態查找方法find_by_api_key(api_key)不起作用(返回零)。同樣的,:

ApiKey.where({:api_key => 'something'}).first 

在sqlite3的,我做了以下內容:

insert into api_keys (id, api_key) values (-1, '12345'); 

如果我現在運行一個選擇:

select api_keys.* from api_keys where api_keys.api_key = '12345'; 

的記錄會被發現。如果我運行從我的應用程序創建

預先存在的數據顯示一個未經過濾的選擇:

select api_keys.* from api_keys; 

如果我嘗試從一個粘貼到我的查詢很長的十六進制字符串找到預先存在的記錄那些預先存在的記錄:

select api_keys.* from api_keys where api_keys.api_key = 'long hex string'; 

然後它不返回任何結果。如果我試試這個:

select api_keys.* from api_keys where api_keys.api_key like 'long hex string'; 

然後我得到一個匹配。

我在api_keys.api_key上創建了一個索引,但沒有任何效果。

此問題會影響我的應用程序中的另一個模型,該模型會使用Digest :: SHA1 :: hexdigest生成類似的隨機十六進制數字串。

詹姆斯

+0

我要補充一點,這個工作對我提到的,直到升級到Rails 3.1的第​​二個模型類。測試在那時開始失敗。 –

回答

8

好吧,我想我已經知道了。問題不在於這是Rails 3.1,而是因爲您可能已經從Ruby 1.8.7移到了Ruby 1.9.2。

在Ruby 1.9中,現在所有的字符串都被編碼了。默認情況下,所有字符串應該是UTF-8,但是,SecureRandom.hex(30)返回的編碼爲ASCII-8BIT

您可以使用此命令在sqlite3的證實了這一點:.dump api_keys,你可能會看到API_KEY場看起來是這樣的:

INSERT INTO "api_keys" VALUES(1,X'376433356530[...]',1);  
INSERT INTO "api_keys" VALUES(1,'1234567890[...]',1); 

第一種是由SecureRandom的產生API_KEY。第二個是通過鍵入控制檯創建的。X表示該字段被編碼爲blob,而不是字符串。

爲了解決這個問題,改變你的fill_api_key這樣:

self.api_key = SecureRandom.hex(30).force_encoding('UTF-8') 

我剛剛有點大的時候這個,所以希望它可以幫助你。

大約有1.9這裏的變化爲String一些不錯的細節:http://blog.grayproductions.net/articles/ruby_19s_string

+0

謝謝!這似乎已經成功了。我不知道我是如何錯過日誌文件中的X. –

0

如果您使用十六進制數字的字符串,它是重要的,如果你想使用其中X = Y選擇,你有一個情況下比賽。與某些數據庫不同,SQLite區分大小寫。

+0

謝謝史蒂夫。這似乎並不是它 - 我在sqlite3中複製和粘貼字符串 - 它都是小寫字母,我使用的都是小寫字母,而且我直接複製字符串。 –

+0

好吧,在上例中,您選擇的INSERT沒有字母十六進制數字。如果直接在SQLite中執行INSERT時使用'1a3bf7'或類似的東西會發生什麼。 SELECT是否找到它?你的Rails應用程序?另外,這個十六進制字符串有多長? –

+0

十六進制字符串的長度是60個字符(也許矯枉過正)。在我的測試中,我輸入了長達70個字符的十進制數字串,然後開始添加字母(小寫,在開始時)高達約80個字符。 –

相關問題