2015-12-02 28 views
1

我建立一個ActiveRecord模型存儲鍵/值對使用早該匹配器來測試`allow_nil`結合`uniqueness`和`scope`

實施例的表 -

|------------------------------| 
| KEY  | VALUE    | 
|----------|-------------------| 
| LOCATION | San Francisco, CA | 
| TITLE | Manager   | 
| LOCATION | New York City, NY | 
|------------------------------| 

這裏的模型 -

class CompanyEnum < ActiveRecord::Base 
    KEYS = [:title, :department, :location] 
    KEYS_ENUM = KEYS.map(&:to_s).map(&:upcase) 

    # `key` column must be one of the above - LOCATION, DEPARTMENT, or TITLE 
    validates(:key, inclusion: KEYS_ENUM, allow_nil: false) 

    # `value` can be anything, but must be unique for a given key (ignoring case) 
    validates(
    :value, 
    uniqueness: { scope: :key, case_sensitive: false }, 
    allow_nil: false 
) 
end 

我使用shoulda matchers來寫這些驗證規範。所以在我的spec文件我有以下兩種規格 -

describe "validations" do 
    it { should_not allow_value(nil).for(:key) } 
    it { should_not allow_value(nil).for(:value) } 
end 

我的問題是,第一次驗證了:key通行證,但對於:value第二驗證失敗。根據模型定義,兩者都使用相同的allow_nil: false選項。

1) CompanyEnum validations value should not allow value to be set to nil 
    Failure/Error: it { should_not allow_value(nil).for(:value) } 
    Expected errors when value is set to nil, 
    got no errors 
    # ./spec/models/company_enum_spec.rb:13:in `block (4 levels) in <top (required)>' 
    # ./spec/support/analytics.rb:4:in `block (2 levels) in <top (required)>' 

是否有使用allow_nil: falseuniqueness:scope: optoins任何邏輯問題?或者它與我命名實際列:key:value(因爲這些似乎足以與其他一些方法衝突)?

謝謝!

+0

爲什麼不直接使用一個存在驗證?我認爲它由於範圍條款而變得混亂。也只是一個性能提到,但你可能想凍結每個字符串和鍵枚舉的數組,否則它們是與每個模型實例一起創建的。 – CWitty

回答

3

allow_nil: false您的唯一性驗證並不意味着nil不是允許的值。這有點誤導。

正如你可能已經知道,在默認情況下,唯一性驗證這種方式工作(由你使用的代碼判斷):

  • 如果有兩個記錄與keyvalue相同的值,那麼與第一個記錄相比,第二個記錄應該是無效的(如果第一個記錄存在於數據庫中)。
  • 如果有兩個記錄具有不同的值keyvalue,則兩個記錄都應該有效。

那麼allow_nil是做什麼的?讓我們來看看the docs不得不說:

:allow_nil - 如果設置爲true,跳過此驗證屬性是否nil(默認爲false)。

所以如果是真的,allow_nil允許兩個記錄與正在驗證(在這種情況下value)屬性nil值共存。

但是您已指定allow_nil: false,這意味着此選項無論如何不適用。

總之,您首次使用allow_value失敗,因爲nil不是key(包含驗證失敗)的有效值。然而,第二次使用通過,因爲nilvalue的有效值(前提條件是沒有現有記錄也有value,nil)。

我的觀點,我想的是,如果你真的想測試你的驗證,你應該使用直接對應於這些驗證匹配器:

it do 
    should validate_inclusion_of(:key). 
    in_array(["TITLE", "DEPARTMENT", "LOCATION"]). 
    allow_nil 
end 

it do 
    should validate_uniqueness_of(:value). 
    scoped_to(:key). 
    case_insensitive 
end 
+0

這樣做很有意義,謝謝!我猜'allow_nil'的目的不是描述字段的值,而是爲了標記天氣,驗證本身應該爲'nil'值運行。看起來有點誤導,正如你提到的,但感謝你清除它 – user2490003

相關問題