(重新)生成一个传递唯一约束的唯一键

时间:2017-04-25 21:46:58

标签: elixir phoenix-framework

我正在为这样的模型生成一个唯一的密钥......

def changeset(%__MODULE__{} = post, attrs) do
  post
  |> generate_key()
  |> unique_constraint(:key)
end

defp generate_key(changeset) do
  key = :crypto.strong_rand_bytes(5)
  |> Base.url_encode64
  |> binary_part(0, 5)

  put_change(changeset, :key, key)
end

这可能不是最好的方法,所以请随意提供其他建议,但我的问题是,当unique_constraint被击中时,重新生成密钥的最佳方法是什么?什么是测试它的最佳方法?

编辑:这不完全是整个架构,它只是简化以简化。我实际上有一个主要ID,以及其他一些领域。

我想要一个将公开分享给不同用户的密钥,每个用户都有不同的密钥,因此它必须是唯一的。它可以超过5个字符,虽然它将通过URL共享,所以我不想太长时间。有一个更复杂的约束,根据密钥和电子邮件地址验证唯一性,所以我并不担心5的长度。无论长度如何,如果unique_constraint是,我希望重新生成它。击中。

1 个答案:

答案 0 :(得分:2)

这是我用来创建随机字符串的代码

@spec random_string(integer) :: binary
def random_string(length) do
  length
  |> :crypto.strong_rand_bytes
  |> Base.url_encode64
  |> binary_part(0, length)
end

unique_constraint的问题在于,在尝试写入数据库之前,您的变更集不会显示约束错误(Repo.insert或Repo.update)

最简单的方法是使用单独的模块来处理插入。像这样:

defmodule PostService do
  def insert_post(params) do
    changeset = Post.changeset(%Post{}, params)
    case Repo.insert changeset do
      {:error, %{errors: constraint_match}} ->  
        # constraint_error is just a placeholder for the correct match
        insert_post(params)
      error_or_ok -> 
        error_or_ok
    end
  end
end

但是,如果您使用UUID,我认为您不必担心碰撞。