我正在为这样的模型生成一个唯一的密钥......
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是,我希望重新生成它。击中。
答案 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,我认为您不必担心碰撞。