2017-01-24 49 views
1

我有一個模型叫Update其中包含列:version這是一個字符串。Rails:使用ActiveRecord與自定義比較器

class Update < ApplicationRecord 
    validates_presence_of :version 
end 

version列包含字符串值如1.0.1。使用Gem::Version,你可以比較的版本號是這樣的:

Gem::Version.new('2.1') > Gem::Version.new('2.0.1') 

我想做一個查詢在那裏我可以version得到所有的記錄超過一定的數量。有沒有辦法將自定義方法傳遞給.where以便我可以使用版本比較器?如:

class Update < ApplicationRecord 
    def version_is_greater_than(that_version) 
    Gem::Version.new(self.version) > Gem::Version.new(that_version) 
    end 
end 

...

Update.where(&:version_is_greater_than) 

正如你可以看到,上述代碼不能正常工作,因爲我需要一個版本字符串傳遞到我似乎無法做到這一點的方法通過&:。有沒有更好的方法來做到這一點,以便我可以比較.where調用中的值?我試圖遠離分裂大/小/等。數字,因爲我只是在那裏重新發明輪子。

+0

我正在使用Postgres。簡單的'1.2.3'格式是可以接受的。這與我的任何寶石版本無關 - 但我認爲比較器至少足夠滿​​足我的需求。 –

+0

我覺得這很容易做到'Update.all.select {| u | Gem :: Version.new(u.version)> Gem :: Version.new(「2.0」)}'但我只是想知道是否有一種方法將它與'.where'結合起來,以根據其他屬性也是如此。 –

回答

1

您不能在數據庫中使用Ruby方法,並且在數據庫中執行where中的所有內容。但是,您可以在數據庫內部實現簡單的major.minor.patch版本號比較。

PostgreSQL支持陣列列和陣列由元件比較元件所以像:如預期的數據庫內

array[1,2,3] < array[1,5,0] 

工作(即與Ruby中的[1,2,3] < [1,5,0]相同)。


一種方法是將你的字符串列轉換爲整數數組,發送版本號到數據庫中的數組,並讓數據庫做比較。遷移如:

connection.execute(%q{ 
    alter table updates 
    alter column version 
    set type int[] using regexp_split_to_array(version, '\\.')::int[] 
}) 

應照顧數據庫。然後,你可以說:

def version_is_greater_than(that_version) 
    self.version > that_version.split('.').map(&:to_i) 
end 

或查詢數據庫:

def self.version_is_greater_than(that_version) 
    where('version > array[?]', that_version.split('.').map(&:to_i)) 
end 

你需要更新的讀取和寫入version s到說明新類型的version列,以及代碼。


或者,你可以離開version在數據庫中的字符串,並使用regexp_split_to_arraywhere電話時你需要比較的東西:

where(%q{ 
    regexp_split_to_array(version, '\\.')::int[] > array[?] 
}, that_version.split('.').map(&:to_i)) 

有PL /紅寶石,允許你在Ruby中編寫存儲過程,但是它已經七年沒有更新了,並且假設Ruby 1.8.7是最新的。我們可以假裝它不存在。

0

不,你不能這樣使用它。

&運算符將一個方法轉換爲一個proc,並在您調用一個接受一個塊的方法(如那些可枚舉的方法)時將它傳遞給參數。查看此線程獲取更多信息。

what is the functionality of "&: " operator in ruby?

where方法不帶塊。當您致電where(...)時,您基本上稱爲WhereChain.new(...)。 Refeter這個位置:

https://github.com/rails/rails/blob/master/activerecord/lib/active_record/relation/query_methods.rb

什麼你正在嘗試做的可以通過包裝方法進入SQL對象,或者只是一個返回SQL字符串的方法來實現。但不幸的是,我不認爲sql(特別是mysql)對字符串(或varchar)有比較操作,如>,<。所以你不能在sql中本地執行它,這意味着,你將無法生成一個sql字符串並將它傳遞給where子句來實現此目的。請參閱SQL Server文檔在這裏:

https://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html#operator_greater-than

由於使用的情況下,也有版本特定的寶石更新的數量非常有限,所以恕我直言,這是安全快速剛剛獲得所有記錄,並在操作紅寶石級別。