Rails 3.1,Ruby 1.9.2,通过activerecord-sqlserver-adapter gem使用SQL Server 2008数据库。我正在使用遗留数据库,所以这不是自愿的。
我遇到了ActiveAdmin的奇怪问题。我之前没有使用过ActiveAdmin,并在看完Railscast后添加了它。遵循标准安装说明,我可以登录管理控制台。
当我添加模型时:
rails generate active_admin:resource Payment
现在可以在ActiveAdmin仪表板上看到模型(复数形式)。但是,当我点击链接时,我收到以下错误:
TinyTds::Error: No column name was specified for column 2 of '__rnt'.: EXEC
sp_executesql N'SELECT TOP (1) [__rnt].* FROM ( SELECT ROW_NUMBER() OVER (ORDER
BY [Payments].[UPaymentID] ASC) AS [__rn], 1 FROM [Payments] ) AS [__rnt]
WHERE [__rnt].[__rn] > (0) ORDER BY [__rnt].[__rn] ASC'
现在,如果我直接在SQL Server数据库上运行它,此查询将返回相同的错误 - 它不喜欢未命名的列“1”。
开始挖掘以了解问题所在。显而易见的地方是activeadmin和activerecord之间的转换,然后是activerecord和SQL Server适配器。这是第一个交叉点的堆栈跟踪:
activerecord (3.1.0) lib/active_record/relation/finder_methods.rb:197:in `exists?'
activeadmin (0.4.2) lib/active_admin/views/pages/index.rb:41:in `items_in_collection?'
activeadmin (0.4.2) lib/active_admin/views/pages/index.rb:20:in `main_content'
看起来像items_in_collection?正在呼唤存在?在已删除订单筛选器的集合上。此时,我们将转交给ActiveRecord。如果我们查看从ActiveRecord到SQL Server适配器的转换,看起来好像已经形成了SELECT语句:
activerecord-sqlserver-adapter (3.1.6) lib/active_record/connection_adapters/sqlserver/database_statements.rb:348:in `do_exec_query'
activerecord-sqlserver-adapter (3.1.6) lib/active_record/connection_adapters/sqlserver/database_statements.rb:24:in `exec_query'
activerecord-sqlserver-adapter (3.1.6) lib/active_record/connection_adapters/sqlserver/database_statements.rb:297:in `select'
activerecord (3.1.0) lib/active_record/connection_adapters/abstract/database_statements.rb:18:in `select_all'
activerecord (3.1.0) lib/active_record/connection_adapters/abstract/query_cache.rb:61:in `block in select_all'
我完全不知道为什么SQL会以它的方式生成。有几个候选问题区域:
activerecord-sqlserver-adapter
宝石的问题。但是,我删除了源代码,并且确实看起来没有任何东西会以这种方式组装此查询。有没有人碰到类似的东西?可能我只需要在整个堆栈中调试我的方式来查看正在发生的事情。想象一下,首先要在这里查看。
编辑:我现在很确定这是activerecord-sqlserver-adapter中的一个错误。一旦我拥有它,我会在这里发布决议。
Edit2:可以在没有ActiveAdmin的情况下重现错误。这与sql server适配器处理偏移查询的方式有关。调用
MyModel.offset(1).exists?
产生相同的错误。我对适配器有一个丑陋的补丁,它通过了所有单元测试,但我会在发出拉取请求之前尝试找到更优雅的解决方案。
答案 0 :(得分:1)
我不确定这是答案,但我修补了我的本地代码,现在你的查询对我有效。
首先,github问题:
https://github.com/rails/rails/issues/1623
然后是arkadiyk修复的拉取请求:
https://github.com/arkadiyk/rails/commit/7e2ddddb303d17adc825ebb691097a93902fa539
基本问题是finder_methods.rb,其中包含第187或188行的现有代码:
relation = relation.except(:select).select("1").limit(1)
生成的未命名列上的MSSQL barfs,因此以下代码修复了它:
relation = relation.except(:select).select("1 as o").limit(1)
希望有所帮助。
答案 1 :(得分:0)
似乎有两种方法可以解决这个问题:将其修复为rails,或者将其修复为activerecord-sqlserver-adapter。
Raels提供的链接可能是解决此问题的正确方法,但拉取请求尚未被接受到rails中。我担心使用修补版本的rails,因为这会迫使我坚持使用我的修补版本,或者继续修补rails轨道。
Al替代方法是在activerecord-sqlserver-adapter中修复此问题。我在这里提交了拉取请求:
https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/171
active-sqlserver-adapter的维护者可能会提出更优雅的修复方法。如果他这样做,我会更新这个答案。