使用 shoulda 匹配器结合 `uniqueness` 和 `scope` 测试 `allow_nil`
Using shoulda matchers to test `allow_nil` in combination with `uniqueness` and `scope`
我正在为存储 key/value 对的 table 构建 ActiveRecord 模型
例子-
|------------------------------|
| 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 编写这些验证的规范。所以在我的规范文件中,我有以下两个规范 -
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: false
与 uniqueness:
和 scope:
optoins 一起使用是否存在任何逻辑问题?或者它与我命名实际列 :key
和 :value
有什么关系吗(因为它们看起来足够通用以与其他一些方法冲突)?
谢谢!
allow_nil: false
在您的唯一性验证中并不意味着 nil
不是允许的值。有点误导。
您可能已经知道,默认情况下,唯一性验证是这样工作的(根据您使用的代码判断):
- 如果有两条记录具有相同的值
key
和value
,那么第二条记录与第一条记录相比应该是无效的(前提是第一条记录存在于数据库中)。
- 如果有两条记录
key
和value
的值不同,那么两条记录都应该有效。
那么allow_nil
是做什么的呢?让我们看看 the docs 怎么说:
:allow_nil
- If set to true
, skips this validation if the attribute is nil
(default is false
).
因此,如果为真,allow_nil
允许两个记录与正在验证的属性的 nil
值共存(在本例中为 value
)。
但是您指定了 allow_nil: false
,这意味着此选项无论如何都不适用。
总之,您第一次使用 allow_value
失败,因为 nil
不是 key
的有效值(包含验证失败)。但是,第二次使用通过了,因为 nil
是 value
的有效值(前提是没有现有记录也具有 nil
的 value
)。
我想我的意思是,如果你真的想测试你的验证,你应该使用直接对应于这些验证的匹配器:
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
我正在为存储 key/value 对的 table 构建 ActiveRecord 模型
例子-
|------------------------------|
| 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 编写这些验证的规范。所以在我的规范文件中,我有以下两个规范 -
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: false
与 uniqueness:
和 scope:
optoins 一起使用是否存在任何逻辑问题?或者它与我命名实际列 :key
和 :value
有什么关系吗(因为它们看起来足够通用以与其他一些方法冲突)?
谢谢!
allow_nil: false
在您的唯一性验证中并不意味着 nil
不是允许的值。有点误导。
您可能已经知道,默认情况下,唯一性验证是这样工作的(根据您使用的代码判断):
- 如果有两条记录具有相同的值
key
和value
,那么第二条记录与第一条记录相比应该是无效的(前提是第一条记录存在于数据库中)。 - 如果有两条记录
key
和value
的值不同,那么两条记录都应该有效。
那么allow_nil
是做什么的呢?让我们看看 the docs 怎么说:
:allow_nil
- If set totrue
, skips this validation if the attribute isnil
(default isfalse
).
因此,如果为真,allow_nil
允许两个记录与正在验证的属性的 nil
值共存(在本例中为 value
)。
但是您指定了 allow_nil: false
,这意味着此选项无论如何都不适用。
总之,您第一次使用 allow_value
失败,因为 nil
不是 key
的有效值(包含验证失败)。但是,第二次使用通过了,因为 nil
是 value
的有效值(前提是没有现有记录也具有 nil
的 value
)。
我想我的意思是,如果你真的想测试你的验证,你应该使用直接对应于这些验证的匹配器:
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