使用Rails 3.1和sqlite3进行开发,测试环境.
在迁移中添加了一个新表:
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)不起作用(返回nil).与:相同:
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生成类似的随机十六进制数字字符串.
詹姆士
好吧,我想我已经弄明白了.问题不在于这是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