我问的问题与强制空字符串为NULL相反;相反,我希望作为空字符串的字段存储为空字符串。我之所以要这样做(甚至与一些人所说的相矛盾),是因为我希望对适用于多种数据库类型(postgres、mysql等)的表有一个部分唯一性约束,如本问题所述。
模式的伪代码基本上是:
Person {
first_name : String, presence: true
middle_name : String, presence: true
last_name : String, presence: true
birth_date : String, presence: true
city_of_birth: String, presence: true
active: tinyint
}
约束条件是,如果一个人是活跃的,那么他必须是唯一的;不活跃的人可能不是唯一的(即,我可以有多个不活跃的约翰·史密斯,但只有一个活跃的约翰·Smith)。
更复杂的是:根据项目规范,用户只需要提供first_name和last_name,其他所有字段都可以为空。
我们当前应用部分唯一性约束的解决方案是使用NULL!=NULL,如果某人未处于活动状态,则将活动tinyint设置为NULL,如果他们处于活动状态则将其设置为1。因此,我们可以在迁移中使用以下rails代码:
add_index :Persons, [first_name, middle_name, last_name, birth_date,
city_of_birth, active], unique:true, name: "unique_person_constraint"
但是,为了使该约束起作用,其他字段都不能为NULL。如果是,那么没有其他填充字段且active=1的两个John Smiths将仍然是"唯一的",因为值为NULL的middle_name字段将彼此不同(因为NULL!=NULL,无论列类型如何)。
然而,当我做时
options = { first_name: "John",
middle_name: "",
last_name: "Smith",
birth_date: "",
city_of_birth: "",
}
person = Person.new(options)
success = person.valid?
success
总是错误的,因为
Middle name can't be blank
City of birth can't be blank
Birth date can't be blank
因此,我需要一种方法来确保对于其他字段,我总是至少有空字符串来强制执行部分唯一性约束。我该怎么做?如果我去掉了模型定义中的presence:true
,那么现在似乎允许使用NULL字段,这很糟糕。
这是Rails 3.2.13,如果需要,我可以提供其他gem和gem版本。
除了presence true,您还可以将allow_blank添加为true,这将允许您保存空字符串。