2013-07-11 59 views
2

我想獲取ID不在數組中的所有活動關係。像這樣:如果過濾器數組爲空,ActiveRecord'where'子句不起作用

@widgets = Widget.where("id not in (?)", [1, 2, 3]) 

這工作正常。它將返回完整的Widget表,除了過濾器數組排除的那些記錄外。但是,如果過濾器數組爲空,則不起作用。

@widgets = Widget.where("id not in (?)", []) 

返回「[]」的時候,我真的想Widget.all

我圍繞着這一工作相當於首先測試如果濾波器陣列是空的,並修改查詢。但是解決方法看起來像是kludge。有沒有辦法表達這個'where'子句,以便在過濾器數組爲空時返回整個表?

回答

2

您可以將範圍添加窗口小部件模型:

scope :excluding_ids, ->(ids) { where('id NOT IN (?)', ids) if ids.any? } 

然後,它只是一個做這件事的,無論你需要它:

@widgets = Widgets.excluding_ids([1,2,3]) 
+0

試過這個,它的工作原理!它沒有解決潛在的問題(爲什麼在過濾器數組中傳遞[]不正確),但添加範圍可以解決問題。雖然我被撕裂了,因爲羅斯的代碼更簡單,但用「[0]」過濾器數組掩蓋問題並不完全正確。 – Monty

+0

ActiveRecord在SQL中將[]轉換爲NULL。所以,你基本上正在運行'SELECT * FROM widgets WHERE id NOT IN(NULL)',這會導致數據庫不返回任何記錄。 –

+0

或者,如果您不想在範圍中執行此操作:'@widgets = ids.any? ? Widget.where(「id not IN(?)」,ids):Widget.all'雖然我不喜歡這樣,因爲它很難閱讀(很多問號)。 –

1

我假設你的ID從1開始,所以你將不會有一個id = 0的小部件。 您可以向數組添加一個零,因此它永遠不會爲空,並且它會返回所有小部件,因爲沒有id = 0。

@widgets = Widget.where("id not in (?)", my_array + [0]) 

這是一種黑客,但它應該工作!

+0

這正是我做:-)解決方法但正如你所說,這是一個破解。 – Monty

+0

@Monty這是一個黑客,但這不是一個真正的鐵軌問題。這個錯誤存在於數據庫級別http://bugs.mysql.com/bug.php?id=12474 –

+0

謝謝@maximus,這有點亮。我正在使用postgres,但該鏈接中的mysql解釋似乎基於ANSI SQL標準傳遞'IN()'。基本上他說'如果你知道答案,就不要查詢數據庫' - 這是浪費資源。 – Monty