ActiveRecord在Ruby 1.9.2-rc1下以ASCII-8Bit返回数据

除了标题之外,当从ActiveRecord加载数据时,尽管我尽最大努力强制编码,但编码始终设置为ASCII-8Bit。 我已经在这里输入了尽可能详细的信息,试图建立一个可以用来帮助我的好错误报告!

该项目使用以下技术:

  • Padrino框架
  • Ruby 1.9.2-rc2(同样是1.9.1和1.9.2-preview3)
  • ActiveRecord的
  • MySQL的

(完整名单)

$ bundle show | ack '(record|padrino)' * activerecord (2.3.8) * padrino (0.9.14) * padrino-admin (0.9.14) * padrino-core (0.9.14) * padrino-gen (0.9.14) * padrino-helpers (0.9.14) * padrino-mailer (0.9.14) 

剧集表:

 mysql> DESCRIBE `episodes`; +----------------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +----------------+--------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | show_id | int(11) | YES | | NULL | | | season_id | int(11) | YES | | NULL | | | episode_number | int(11) | YES | | NULL | | | title | varchar(255) | YES | | NULL | | | year | int(11) | YES | | NULL | | +----------------+--------------+------+-----+---------+----------------+ 6 rows in set (0.02 sec) mysql> SHOW CREATE TABLE episodes; Table: episodes Create Table: CREATE TABLE `episodes` ( `id` int(11) NOT NULL AUTO_INCREMENT, `show_id` int(11) DEFAULT NULL, `season_id` int(11) DEFAULT NULL, `episode_number` int(11) DEFAULT NULL, `title` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, `year` int(11) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=74332 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci mysql> SHOW CREATE DATABASE development; +-------------+--------------------------------------------------------------------------------------------------------+ | Database | Create Database | +-------------+--------------------------------------------------------------------------------------------------------+ | development | CREATE DATABASE `development` /*!40100 DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci */ | +-------------+--------------------------------------------------------------------------------------------------------+ 1 row in set (0.00 sec) 

正如您所看到的,数据库肯定认为事情应该是UTF-8; 和数据库适配器:

 ActiveRecord::Base.configurations[:development] = { :adapter => 'mysql', :encoding => 'utf8', :reconnect => false, :database => "development", :pool => 5, :username => 'root', :password => '', :host => 'localhost', } 

在检查活动记录连接时,在控制台中回显:

 ruby-1.9.2-rc1 > ActiveRecord::Base.connection DEBUG - [06/Jul/2010 19:24:32] "SQL (0.1ms) SET NAMES 'utf8'" DEBUG - [06/Jul/2010 19:24:32] "SQL (0.1ms) SET SQL_AUTO_IS_NULL=0" => #<ActiveRecord::ConnectionAdapters::MysqlAdapter:0x0000010936fa88 @logger=#<Padrino::Logger:0x00000101587198 @buffer=[], @auto_flush=true, @level=0, @log=#<IO:>, @mutex=#, @format_datetime="%d/%b/%Y %H:%M:%S", @format_message="%s - [%s] \"%s\"">, @connection=#, @runtime=0.2608299255371094, @last_verification=0, @query_cache_enabled=false, @config={:adapter=>"mysql", :encoding=>"utf8", :reconnect=>false, :database=>"development", :pool=>5, :username=>"root", :password=>"", :host=>"localhost"}, @connection_options=["localhost", "root", "", "development", nil, nil, 131072], @quoted_table_names={}, @quoted_column_names={}> 

ruby-1.9.2-rc1> ActiveRecord :: Base.connection.encoding

Ruby应该知道语言,这是我的$ locale

 LANG="en_GB.UTF-8" LC_COLLATE="en_GB.utf-8" LC_CTYPE="en_GB.utf-8" LC_MESSAGES="en_GB.utf-8" LC_MONETARY="en_GB.utf-8" LC_NUMERIC="en_GB.utf-8" LC_TIME="en_GB.utf-8" LC_ALL= 

虽然Ruby没有设置Encoding.default_internal

 $ irb --simple-prompt ruby-1.9.2-rc1 > Encoding.default_internal => nil 

我在我的应用程序的config/boot.rb中添加了一个片段,如下所示:

 if Kernel.const_defined?("Encoding") and Encoding.respond_to?(:find) and Encoding.respond_to?(:default_internal) Encoding.default_internal = Encoding.find('UTF-8') end 

这完全符合您的预期……但是是黑客,并没有解决问题。

以下是原位问题的输出:

 ruby-1.9.2-rc1 > e = Episode.new DEBUG - [06/Jul/2010 19:29:14] "SQL (0.1ms) SET NAMES 'utf8'" DEBUG - [06/Jul/2010 19:29:14] "SQL (0.1ms) SET SQL_AUTO_IS_NULL=0" DEBUG - [06/Jul/2010 19:29:14] "Episode Columns (0.8ms) SHOW FIELDS FROM `episodes`" => # ruby-1.9.2-rc1 > e.title => nil ruby-1.9.2-rc1 > nt = "New Title" => "New Title" ruby-1.9.2-rc1 > nt.encoding => # ruby-1.9.2-rc1 > e.title = nt => "New Title" ruby-1.9.2-rc1 > e.title.encoding => # ruby-1.9.2-rc1 > e.save DEBUG - [06/Jul/2010 19:29:48] "SQL (0.1ms) BEGIN" DEBUG - [06/Jul/2010 19:29:48] "Episode Create (0.2ms) INSERT INTO `episodes` (`show_id`, `season_id`, `episode_number`, `title`, `year`) VALUES(NULL, NULL, NULL, 'New Title', NULL)" DEBUG - [06/Jul/2010 19:29:48] "SQL (0.4ms) COMMIT" => true ruby-1.9.2-rc1 > Episode.find_by_title(nt).title.encoding DEBUG - [06/Jul/2010 19:30:04] "Episode Load (29.5ms) SELECT * FROM `episodes` WHERE (`episodes`.`title` = 'New Title') LIMIT 1" => # ruby-1.9.2-rc1 > 

我通过覆盖访问器取得了一些成功,并将它们重新定义为:

 class Episode # ... def title title.encode! end # ... end 

哪里encode! 这里定义的是1.9的API文档 – 在这里引用它“没有选项会返回str转码为Encoding.default_internal的str副本。”

虽然我的解决方案是成功的,但我更倾向于让UTF-8从数据库中出来,这就是我的代码似乎表明的情况。

您可能需要ruby-mysql gem,它是1.9中的编码感知,而不是更常见的mysql gem,而不是。 有关详情,请参阅我的博客

mysql2 gem也应该解决这个问题,并且比ruby-mysql gem快得多。