如何在 Phoenix 的两个模型中处理具有唯一约束的一对一关联
How to handle one-to-one association with unique constraints in both models in Phoenix
我有两个模型,User
和 Profile
以及一个新用户表单,其配置文件的用户名字段为 inputs_for
。
这是这些代码:
用户 ->
defmodule MyApp.User do
use MyApp.Web, :model
schema "users" do
field :email, :string
field :password, :string, virtual: true
field :crypted_password, :string
has_one :profile, MyApp.Profile
timestamps
end
def changeset(model, params \ :empty) do
model
|> cast(params, ~w(email password), ~w())
|> validate_length(:email, min: 5, max: 240)
|> validate_format(:email, ~r/\w+\@\w+\.\w+/)
|> unique_constraint(:email)
|> validate_confirmation(:password)
|> validate_length(:password, min: 8, max: 240)
end
end
个人资料 ->
defmodule MyApp.Profile do
use MyApp.Web, :model
schema "profiles" do
field :username, :string
belongs_to :user, MyApp.User, foreign_key: :user_id
timestamps
end
def changeset(model, params \ :empty) do
model
|> cast(params, ~w(username), ~w())
|> validate_length(:username, min: 4, max: 240)
|> unique_constraint(:username)
end
end
控制器创建方法的代码 ->
def create(conn, %{"user" => user_params}) do
profile_changeset = Profile.changeset(%Profile{}, user_params["profile"])
user_changeset = User.changeset(%User{profile: profile_changeset}, user_params)
case Repo.insert(user_changeset) do
{:ok, _changeset} ->
redirect conn, to: main_page_path(conn, :index)
{:error, changeset} ->
render conn, "new.html", user_changeset: changeset
end
end
有人可以帮我处理在事务中创建 user
和 profile
的控制器代码吗?如果验证失败,再次呈现错误的表单?对我来说主要的困难是显示我从唯一性约束中得到的错误,这些错误仅在 Repo
插入期间添加,因此 valid?
方法不会添加它们 ...
我花了几个小时试图让它工作,但我不能正确地完成它,当某些事情有效时,其他事情却不...
错误在于您的控制器操作:
profile_changeset = Profile.changeset(%Profile{}, user_params["profile"])
user_changeset = User.changeset(%User{profile: profile_changeset}, user_params)
与其自己构建配置文件变更集并直接在用户中设置它(这是错误的,用户应该存储配置文件,而不是配置文件变更集),不如将所有内容传递给:
user_changeset = User.changeset(%User{}, user_params)
然后通过将 "profile" 声明为必填字段来告诉用户自动为您转换配置文件变更集:
|> cast(params, ~w(email password profile), ~w())
我们将向 master 推送一个修复程序,这样我们至少会在这些情况下引发错误。
我有两个模型,User
和 Profile
以及一个新用户表单,其配置文件的用户名字段为 inputs_for
。
这是这些代码:
用户 ->
defmodule MyApp.User do
use MyApp.Web, :model
schema "users" do
field :email, :string
field :password, :string, virtual: true
field :crypted_password, :string
has_one :profile, MyApp.Profile
timestamps
end
def changeset(model, params \ :empty) do
model
|> cast(params, ~w(email password), ~w())
|> validate_length(:email, min: 5, max: 240)
|> validate_format(:email, ~r/\w+\@\w+\.\w+/)
|> unique_constraint(:email)
|> validate_confirmation(:password)
|> validate_length(:password, min: 8, max: 240)
end
end
个人资料 ->
defmodule MyApp.Profile do
use MyApp.Web, :model
schema "profiles" do
field :username, :string
belongs_to :user, MyApp.User, foreign_key: :user_id
timestamps
end
def changeset(model, params \ :empty) do
model
|> cast(params, ~w(username), ~w())
|> validate_length(:username, min: 4, max: 240)
|> unique_constraint(:username)
end
end
控制器创建方法的代码 ->
def create(conn, %{"user" => user_params}) do
profile_changeset = Profile.changeset(%Profile{}, user_params["profile"])
user_changeset = User.changeset(%User{profile: profile_changeset}, user_params)
case Repo.insert(user_changeset) do
{:ok, _changeset} ->
redirect conn, to: main_page_path(conn, :index)
{:error, changeset} ->
render conn, "new.html", user_changeset: changeset
end
end
有人可以帮我处理在事务中创建 user
和 profile
的控制器代码吗?如果验证失败,再次呈现错误的表单?对我来说主要的困难是显示我从唯一性约束中得到的错误,这些错误仅在 Repo
插入期间添加,因此 valid?
方法不会添加它们 ...
我花了几个小时试图让它工作,但我不能正确地完成它,当某些事情有效时,其他事情却不...
错误在于您的控制器操作:
profile_changeset = Profile.changeset(%Profile{}, user_params["profile"])
user_changeset = User.changeset(%User{profile: profile_changeset}, user_params)
与其自己构建配置文件变更集并直接在用户中设置它(这是错误的,用户应该存储配置文件,而不是配置文件变更集),不如将所有内容传递给:
user_changeset = User.changeset(%User{}, user_params)
然后通过将 "profile" 声明为必填字段来告诉用户自动为您转换配置文件变更集:
|> cast(params, ~w(email password profile), ~w())
我们将向 master 推送一个修复程序,这样我们至少会在这些情况下引发错误。