ActiveAdmin查询期间缺少列名称

时间:2012-02-22 19:25:42

标签: ruby-on-rails activerecord activeadmin

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会以它的方式生成。有几个候选问题区域:

  1. 我正在使用奇数架构处理遗留数据库。我必须在我的模型中设置表名和主键名。我不认为这是问题,因为即将出现的查询似乎使用了适当的主键和表名。
  2. activerecord-sqlserver-adapter宝石的问题。但是,我删除了源代码,并且确实看起来没有任何东西会以这种方式组装此查询。
  3. 有没有人碰到类似的东西?可能我只需要在整个堆栈中调试我的方式来查看正在发生的事情。想象一下,首先要在这里查看。

    编辑:我现在很确定这是activerecord-sqlserver-adapter中的一个错误。一旦我拥有它,我会在这里发布决议。

    Edit2:可以在没有ActiveAdmin的情况下重现错误。这与sql server适配器处理偏移查询的方式有关。调用

    MyModel.offset(1).exists?
    

    产生相同的错误。我对适配器有一个丑陋的补丁,它通过了所有单元测试,但我会在发出拉取请求之前尝试找到更优雅的解决方案。

2 个答案:

答案 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的维护者可能会提出更优雅的修复方法。如果他这样做,我会更新这个答案。