一个小型项目,历史数据库是SQL2005,不能更改数据库,所以折腾了一下午,到处查资料,终于成功的让Ruby1.8.7+Rails2.3.4在SQL2005上跑起来了。
安装sqlserver的驱动:gem install activerecord-sqlserver-adapter
安装dbi (0.4.1)后,直接使用ADO来访问SQL Server,提示无法打开ADO驱动,原来是缺少了ADO.rb这个文件,下载DBI的老版本(0.2.*),将lib/dbd_ado/ADO.rb文件拷贝到X:/ruby/lib/ruby/site_ruby/1.8/DBD/ADO/ADO.rb,再次连接数据库仍然提示无法连接,修改database.yml:
development:
adapter: sqlserver
database: database
username: user
password: pwd
host: .\SQLEXPRESS
mode: DBI:ADO
provider: SQLNCLI
注意host那里,不能填localhost,也不能填127.0.0.1,否则无法连接到数据库,不知道为什么。
现在可以正常连接到数据库了,但是查询出来的结果仍然为乱码,在database.yml中设置encoding无效,解决方法为:在environment.rb添加下面代码
require 'win32ole'
WIN32OLE.codepage = WIN32OLE::CP_UTF8
然后一切正常,不知道以后还会不会遇到啥莫名其妙的问题。
PS:Ruby中ADO连接SQLServer的方式已经不再推荐使用,ADO.rb已经年久失修了,貌似有很多问题。
使用ODBC的方式链接SQLServer:
当然第一步要配好ODBC数据源,然后再修改database.yml:
development:
adapter: sqlserver
mode: ODBC
username: urname
password: ***
dsn: urdsn
这时候Rails已经可以成功连接到SQLServer了,但是不能查询数据,查询时会报错:
wrong number of arguments (2 for 1)
需要修改 ruby\lib\ruby\1.8\delegate.rb 这个文件,
第166行和273行定义的方法需要修改为:
def respond_to?(m, include_private = false) # :nodoc:
return true if super
return @_dc_obj.respond_to?(m, include_private)
end
然后连接数据库查询不会再报错,不过查询出来的中文是GBK编码的,如果放在页面上显示,需要手动转换,比较麻烦。查看ruby\lib\ruby\gems\1.8\gems\activerecord-sqlserver-adapter-2.2.22\lib\active_record\connection_adapters\sqlserver_adapter.rb这个文件,第53行:
value.force_encoding('UTF-8') rescue value
由于force_encoding是Ruby1.9里面新增的方法,所以在1.8下面这行代码始终返回value,而没有进行编码转换,既然知道了查询出来的结果是GBK编码的,那暂时用Iconv强制转换一下好了:
value.force_encoding('UTF-8') rescue Iconv.conv('UTF-8','GBK',value) rescue value
至此查询显示乱码问题搞定,在对数据库进行修改操作和根据用户输入进行查询时,还得手工进行转换,再过几年Ruby社区迁移到1.9平台上后这个问题应该就会消失掉了。
在使用过程中发现activerecord-sqlserver-adapter (2.2.22)的分页有问题,真是多灾多难啊,继续修改上面的那个sqlserver_adapter.rb文件,第467行那一大段修改为:
if options[:limit] and options[:offset]
sql.sub!(/ORDER BY.*$/i, '')
sql.sub!(/SELECT/i,
"SELECT row_number() over( order by #{options[:order]} ) as row_num, \n")
sql.replace("select top #{options[:limit]} * from (#{sql}) as tmp_table1 \n" +
"where row_num > #{options[:offset]}")
end
这种修改只对于SQLServer2005以上版本有效,由于使用了order by,在查询中如果没有指定:order就会报错,继续修改will_paginate的finder.rb,在第80行args << find_options前面加上find_options[:order] ||= primary_key:
WillPaginate::Collection.create(page, per_page, total_entries) do |pager|
count_options = options.except :page, :per_page, :total_entries, :finder
find_options = count_options.except(:count).update(:offset => pager.offset, :limit => pager.per_page)
find_options[:order] ||= primary_key
args << find_options
# @options_from_last_find = nil
pager.replace(send(finder, *args) { |*a| yield(*a) if block_given? })
# magic counting for user convenience:
pager.total_entries = wp_count(count_options, args, finder) unless pager.total_entries
end
至此分页问题解决。sqlserver-adapter的作者目前正致力与解决该驱动和Rails3.0的兼容性,承诺以后会对分页语句进行修改,不知道在哪个版本里面可以解决。