rails migration唯一为true但允许空值

时间:2017-08-16 14:08:40

标签: ruby-on-rails postgresql

我最初进行了这次迁移:

  def change
    add_column :users, :provider, :string, null: false, default: "email"
    add_column :users, :uid, :string, null: false, default: ""

    add_index :users, [:uid, :provider], unique: true
  end

但在我的应用程序中,用户无需oauth身份验证即可使用omniauth,用户名和密码登录。因此,在许多情况下,uid和provider将为null。所以我创建了以下迁移:

  def change
    change_column_default :users, :provider, nil
    change_column_default :users, :uid, nil
  end

但是当我尝试在Rails中将提供者或uid设置为nil时,我得到PG::NotNullViolation: ERROR

u = User.first
u.provider = nil
u.save!
   (0.4ms)  BEGIN
  SQL (1.5ms)  UPDATE "users" SET "updated_at" = $1, "provider" = $2 WHERE "users"."id" = $3  [["updated_at", 2017-08-16 00:01:34 UTC], ["provider", nil], ["id", 1]]
   (0.5ms)  ROLLBACK
ActiveRecord::StatementInvalid: PG::NotNullViolation: ERROR:  null value in column "provider" violates not-null constraint
DETAIL:  Failing row contains 

迁移中显示unique: true会阻止设置空值。我怎么能绕过这个?

2 个答案:

答案 0 :(得分:0)

您在第一次迁移中将列设置为 null:false ,这会导致PG :: NotNullViolation异常。需要将其设置为true以允许两列中都包含空值。编写新的迁移以设置null:true应该按如下方式解决问题。

def change
   change_column_null :users, :provider, true
   change_column_null :users, :uid, true
end

同样低于索引可能不起作用(RecordNotUnique异常会因为设置唯一:true而引发),因为您将有多行同时具有空值的uid和provider。因此需要删除此索引。

add_index :users, [:uid, :provider], unique: true

答案 1 :(得分:0)

除此之外:

  def change
    change_column :users, :provider, :string, null: true
    change_column :users, :uid, :string, null: true
    remove_index :users, [:uid, :provider]
  end

随后会允许空值但在数据库级别消除两个字段约束,我在模型级别执行此操作:

validates :provider, uniqueness: { scope: :uid }, allow_nil: true