2012-02-22 51 views
0

Rails 3.1,Ruby 1.9.2,通過activerecord-sqlserver-adapter gem使用SQL Server 2008數據庫。我正在使用遺留數據庫,所以這不是自願的。在ActiveAdmin查詢期間缺少列名稱

我遇到了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寶石。但是,我拉取了源代碼,並且確實看起來沒有任何東西會以這種方式組裝這個查詢。

有沒有人碰到過類似的東西?這可能是我只需要在整個堆棧中調試我的方式以查看發生了什麼。首先,儘管它首先在這裏檢查。

編輯:我現在很確定這是activerecord-sqlserver-adapter中的一個錯誤。一旦擁有了,我會在這裏發佈解決方案。

Edit2:可以在沒有ActiveAdmin的情況下重現錯誤。這與sql server適配器處理偏移量查詢的方式有關。調用

MyModel.offset(1).exists? 

產生相同的錯誤。我對通過所有單元測試的適配器有一個醜陋的補丁,但我會在提出請求之前嘗試找到更優雅的解決方案。

回答

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) 

希望有所幫助。

+0

謝謝。對於解決這個問題的恰當地點,我感慨萬分。很顯然,rails可以通過別名選擇1的列來使我們的生活更輕鬆,但是我想不應該這樣做,因爲這更像是數據庫特有的問題。我在activerecord-sqlserver-adapter上有一個修補程序,可以完成同樣的事情,但以更加醜陋的方式執行(基本上在選擇處理期間訪問節點,並在節點僅爲「1」時追加別名列)。我會發佈一個答案以及鏈接回我的拉請求。 – 2012-03-08 14:00:52

+0

同意。我還可以看到一個通用適配器功能,它可以生成臨時列名稱,然後從查詢和處理結束時的結果集中清除它們。這將允許適配器管理它引入的列,以及可能允許用戶爲列名指定不同的生成器。只是一個想法。我沒有仔細查看代碼,看看什麼是最合理的。 – Raels 2012-03-23 13:48:30

0

似乎有兩種方法可以解決這個問題:在rails中修復它,或者在activerecord-sqlserver-adapter中修復它。

Raels提供的鏈接可能是解決此問題的正確方法,但是,pull請求尚未被接受到rails中。我擔心使用補丁版本的rails,因爲這會迫使我堅持使用補丁版本,或者隨着rails的發展繼續補丁。

另一種方法是在activerecord-sqlserver-adapter中修復此問題。我在這裏提交pull請求:

https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/171

這有可能是主動SQLSERVER適配器的維護者會拿出一個更優雅的修復。如果他這樣做,我會更新這個答案。