我想强制电子邮件在数据库级别是唯一的,但我也想允许空电子邮件值。迁移时出现以下错误。
当前架构
create_table "users", force: true do |t|
t.string "email", default: ""
...
end
add_index "users", ["email"], name: "index_users_on_email"
尝试迁移
remove_index :users, [:email]
change_column :users, :email, :string, :null => true
add_index :users, [:email], unique: true
迁移错误
== RemoveUniqueEmailFromUsers: reverting =====================================
-- remove_index(:users, [:email])
-> 0.0437s
-- change_column(:users, :email, :string, {:null=>true})
-> 0.2664s
-- add_index(:users, [:email], {:unique=>true})
rake aborted!
An error has occurred, this and all later migrations canceled:
SQLite3::ConstraintException: indexed columns are not unique: CREATE UNIQUE INDEX "index_users_on_email" ON "users" ("email")
答案 0 :(得分:0)
尝试删除default: ""
。我认为你有矛盾的配置。
空字符串不是零。
答案 1 :(得分:0)
问题是我创建的最后一个用户收到了''的电子邮件。在销毁此用户后,迁移继续进行。
答案 2 :(得分:0)
如果您在运行SQLite::ConstraintException
之后看到$ rake db:migrate
:
SQLite::ConstraintException : indexed columns are not unique CREATE UNIQUE INDEX "index_users_on_email" ON "users"
...并且您在开发环境中工作,并且您不需要开发数据库中的数据,您可以相当快地解决此问题。
您可以查看数据库中是否有现有用户,并将其全部删除:
$ rails console
> User.count
=> 4
> User.destroy_all
> ...
> User.count
=> 0
然后,您可以再次运行$ rake db:migrate
,并且迁移应该成功运行。
如果您不确定,可以运行$ rake db:migrate:status
。如果所有迁移都是" up,"然后您的迁移已成功运行。
以下是如何理解问题:
您的现有用户没有电子邮件值(用户表没有电子邮件属性)。
运行迁移时,第一部分会添加电子邮件列。
现在,您的所有用户都有一个电子邮件属性,但数据库中的值为空。
迁移的最后一部分尝试添加索引,条件是值是唯一的(unique: true
指定的内容)。
唯一约束无法添加到数据库,因为您现在有一个users表的电子邮件列,它们都具有空值,使其成为非唯一值。 SQLite抛出错误,声明您无法向具有非唯一值的列添加唯一约束。
如果您尝试在生产模式下将此约束添加到数据库列,这可能是一件好事!感谢您保护我们,SQLite!
一旦你理解了这个问题,就可以看到还有其他可能的解决方案,但是如果你在新应用程序的开发环境中,这可能会满足你的需求。