sqlite3 varchar与"like"匹配但不是"="

Jam*_*coe 2 sqlite ruby-on-rails-3.1

使用Rails 3.1和sqlite3进行开发,测试环境.

在迁移中添加了一个新表:

create_table :api_keys do |t|
  t.string :api_key
  t.integer :user_id
  t.timestamps
end
Run Code Online (Sandbox Code Playgroud)

这会生成一个包含以下模式的表:

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
Run Code Online (Sandbox Code Playgroud)

在ActiveRecord模型中:

before_create :fill_api_key

private

def fill_api_key
  self.api_key = SecureRandom.hex(30)
end
Run Code Online (Sandbox Code Playgroud)

ActiveRecord的动态查找器方法find_by_api_key(api_key)不起作用(返回nil).与:相同:

ApiKey.where({:api_key => 'something'}).first
Run Code Online (Sandbox Code Playgroud)

在sqlite3中,我执行以下操作:

insert into api_keys (id, api_key) values (-1, '12345');
Run Code Online (Sandbox Code Playgroud)

如果我现在运行一个选择:

select api_keys.* from api_keys where api_keys.api_key = '12345';
Run Code Online (Sandbox Code Playgroud)

记录将被找到.

如果我运行未经过滤的选择,则会显示从我的应用程序创建的预先存在的数据:

select api_keys.* from api_keys;
Run Code Online (Sandbox Code Playgroud)

如果我尝试通过将一个预先存在的记录中的长十六进制字符串粘贴到我的查询中来查找预先存在的记录:

select api_keys.* from api_keys where api_keys.api_key = 'long hex string';
Run Code Online (Sandbox Code Playgroud)

然后它不返回任何结果.如果我尝试这样做:

select api_keys.* from api_keys where api_keys.api_key like 'long hex string';
Run Code Online (Sandbox Code Playgroud)

然后我得到一个匹配.

我在api_keys.api_key上创建了一个索引但是没有效果.

此问题会影响我的应用程序中的另一个模型,该模型使用Digest :: SHA1 :: hexdigest生成类似的随机十六进制数字字符串.

詹姆士

Tim*_*van 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);
Run Code Online (Sandbox Code Playgroud)

第一个是SecureRandom生成的api_key.第二个是通过键入控制台创建的.X表示字段编码为blob,而不是字符串.

要解决这个问题,请fill_api_key将此更改为:

self.api_key = SecureRandom.hex(30).force_encoding('UTF-8')
Run Code Online (Sandbox Code Playgroud)

我只是有点大的时间,所以希望它可以帮助你.

关于1.9中String的更改有一些很好的细节:http://blog.grayproductions.net/articles/ruby_19s_string