我正在使用Devise构建Rails应用程序进行身份验证,其默认数据库迁移设置以下列:
## Database authenticatable
t.string :email, null: false, default: ""
t.string :encrypted_password, null: false, default: ""
同时设置null: false
和default: ""
的目的是什么?
我的理解是null: false
有效地创建了一个值:即,尝试在该列中保存具有NULL
值的记录将在数据库级别失败,不依赖于模型的任何验证。
但是default: ""
基本上解除了这一点,只需在保存之前将NULL
值转换为空字符串即可。
我理解,对于可选列,您希望拒绝NULL
值,以确保该列中的所有数据属于同一类型。但是,在这种情况下,电子邮件和密码在用户身份验证模型上绝对是非可选属性。我确定模型中有验证可确保您无法创建具有空电子邮件地址的用户,但是为什么要在此处设置default: ""
?它有什么好处或者防止我没有考虑过的一些边缘案例?
答案 0 :(得分:3)
null: false
。无论您创建新表还是更新现有表,都是如此。NULL
的新列。在这种情况下,您必须使用default: ""
覆盖此行为,否则它将与null: false
冲突,并且migraiton将失败。 Devise使用两个单独的模板来构建迁移:migration.rb
用于创建新表,migration_existing.rb
用于更新现有表(请参阅source on GitHub)。两个模板都调用相同的migration_data
method来生成有问题的行(即,指定null: false, default: ""
的行),但如上所述,default: ""
只是真的与后一种情况相关(更多见O. Jones’ answer)。
所以对你的问题的简短回答,特别是在Devise迁移的情况下,是“因为生成器使用的借用代码并不总是适用,但仍然没有破坏任何东西。”
UNIQUE
列的考虑因素:请注意,在大多数流行的SQL引擎uniquely indexed columns can still contain multiple rows of NULL
values中,只要它们不是必需的(自然)。但是,创建新列的效果是和唯一(即 null: false
,default: ""
和{ {1}})无法添加:数据库引擎尝试使用每行中的空字符串填充新列,这与unique: true
约束冲突并导致迁移失败。
(此机制失败的唯一情况是,如果表中只有一行 - 它会为新列获取一个空字符串值,这会自然地传递唯一性约束,因为它是唯一的记录。)
另一种看待它的方法可能是这些选项是一种安全机制,阻止您运行不应该运行的迁移(即追溯性地将已填充的表添加到已填充的表中)
答案 1 :(得分:1)
某些应用程序软件会对NULL值进行gack,但不会对零长度文本字符串进行gack。在Oracle中,它们是相同的,但不是在MySQL中。
在更改表以添加列时,事情变得有趣。在这种情况下,默认值是必需的,因此DBMS可以填充新列。
答案 2 :(得分:0)
插入类型有所不同。例如,假设您有一个new_table
表格,以便:
CREATE TABLE IF NOT EXISTS `new_table` (
`col1` VARCHAR(10) NOT NULL,
`col2` VARCHAR(10) NOT NULL DEFAULT '',
`col3` VARCHAR(10) NULL DEFAULT '');
当您使用NULL
的显式插入时,您将获得NULL
:
INSERT INTO new_table(col1,col2,col3) VALUES('a','b',NULL);
'a','b',NULL
对于col2
相同的技巧会导致错误:
INSERT INTO new_table(col1,col2,col3) VALUES('a',NULL,'c');
但是当您使用隐式插入NULL
时,您将获得默认值:
INSERT INTO new_table(col1,col2) VALUES('a','b');
'a','b',''
意味着设置默认值不会阻止NULL
断言到此列,而只会在未明确指定值时使用。
答案 3 :(得分:0)
我认为这是因为 MySQL 的“严格模式”不允许您在不提供默认值的情况下禁止空值。
来自 mysql 文档:https://dev.mysql.com/doc/refman/8.0/en/data-type-defaults.html
<块引用>对于没有显式 DEFAULT 子句的 NOT NULL 列的数据录入,如果 INSERT 或 REPLACE 语句不包含该列的值,或者 UPDATE 语句将该列设置为 NULL,MySQL 根据 SQL 模式处理该列当时生效:如果启用了严格的 SQL 模式,事务表会发生错误并回滚语句。对于非事务性表,会发生错误,但如果多行语句的第二行或后续行发生这种情况,则会插入前面的行。如果未启用严格模式,MySQL 会将列设置为列数据类型的隐式默认值。