2011-09-15 62 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个字符。 –

相关问题