如何解决Phoenix / Elixir / Ecto-unique_constraint无法使用名称选项
我希望发生的事情:当尝试插入具有现有用户名的角色时,请致电Repo.insert向我返回更改集,其中包含错误信息。
正在发生的事情: Ecto提出了一个硬性例外
我在Phoenix项目中遇到以下错误。
** (exit) an exception was raised:
** (Ecto.ConstraintError) constraint error when attempting to insert struct:
* personas_username_index (unique_constraint)
If you would like to stop this constraint violation from raising an
exception and instead add it as an error to your changeset,please
call `unique_constraint/3` on your changeset with the constraint
`:name` as an option.
The changeset has not defined any constraint.
因此,我遵循了它的建议,并在数据库personas_username_index
中添加了唯一索引的名称。这个唯一索引肯定存在于真正的基础数据库中。
这是我的模式:
defmodule Poaster.Persona do
use Ecto.Schema
import Ecto.Changeset
alias Poaster.User
schema "personas" do
belongs_to :user,User
field :background_image_url,:string
field :bio,:string
field :name,:string
field :profile_image_url,:string
field :username,:string
timestamps()
end
@doc false
def changeset(persona,attrs) do
persona
|> cast(attrs,[:username,:name,:bio,:profile_image_url,:background_image_url,:user])
|> validate_required([:username])
|> unique_constraint(:username,name: :personas_username_index)
end
end
这是我的控制器代码:
def create(conn,%{"username" => username}) do
# First attempt
# result = Ecto.build_assoc(conn.assigns[:signed_user],:personas,%{ username: username })
# IO.inspect(result)
# result = Repo.insert(result)
# IO.inspect(result)
user = conn.assigns[:signed_user]
result = Repo.insert(%Persona{username: username,user: user})
case result do
{:ok,persona} ->
conn
|> put_status(:created)
|> json(persona_data(persona))
{:error,_changeset} ->
conn
|> put_status(:internal_server_error)
|> json(%{
success: false,error: %{
detail: "There was an error saving your username!"
}
})
end
end
defp persona_data(persona) do
%{
id: persona.id,background_image_url: persona.background_image_url,bio: persona.bio,inserted_at: persona.inserted_at,name: persona.name,profile_image_url: persona.profile_image_url,updated_at: persona.updated_at,username: persona.username
}
end
迁移文件:
defmodule Poaster.Repo.Migrations.CreatePersonas do
use Ecto.Migration
def change do
create table(:personas) do
add :username,:string,null: false
add :name,:string
add :bio,:string
add :profile_image_url,:string
add :background_image_url,:string
add :user_id,references(:users,on_delete: :nothing),null: false
timestamps()
end
create unique_index(:personas,[:username])
create index(:personas,[:user_id])
end
end
解决方法
我认为您应该插入一个变更集,而不是直接插入架构,以便能够捕获错误,如文档所述:
https://hexdocs.pm/ecto/Ecto.Changeset.html#unique_constraint/3-complex-constraints
您正在通过unique_constraint/3
函数调用Persona.changeset/2
,但是没有在控制器代码中调用Persona.changeset/2
。
我认为您应该替换以下行:
result = Repo.insert(%Persona{username: username,user: user}
作者:
result = %Persona{}
|> Persona.changeset(%{username: username,user: user})
|> Repo.insert()
或者更确切地说,在执行此操作的上下文中定义一个create_persona/1
函数,然后从您的控制器调用此函数(至少这是生成器对其进行组织的方式),可能更习惯。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。