[英]Custom validations for changeset Elixir/Phoenix
我有一个league
模型,这个league
has_many Teams
。 我只希望用户能够在每个联赛中创建一支球队。 我发现此验证很棘手。 这是我目前正在尝试的方法。
def changeset(%Team{} = team, attrs \\ %{}) do
team
|> cast(attrs, [:name, :league_id, :user_id])
|> validate_required([:name, :league_id, :user_id])
|> one_team_per_user_for_leagues
end
defp one_team_per_user_for_leagues(team) do
if team.changes == %{} do
team
else
league = Repo.get!(League, team.changes[:league_id]) |> Repo.preload(:teams)
Enum.map(league.teams, fn(team) -> team = team end) |> Enum.any?
end
end
但我收到此错误: no function clause matching in Ecto.Repo.Schema.insert/4
Request: POST /teams
** (exit) an exception was raised:
** (FunctionClauseError) no function clause matching in Ecto.Repo.Schema.insert/4
(ecto) lib/ecto/repo/schema.ex:157: Ecto.Repo.Schema.insert(Statcasters.Repo, Ecto.Adapters.Postgres, false, [])
(statcasters) lib/statcasters_web/controllers/team_controller.ex:21: StatcastersWeb.TeamController.create/2
(statcasters) lib/statcasters_web/controllers/team_controller.ex:1: StatcastersWeb.TeamController.action/2
(statcasters) lib/statcasters_web/controllers/team_controller.ex:1: StatcastersWeb.TeamController.phoenix_controller_pipeline/2
(statcasters) lib/statcasters_web/endpoint.ex:1: StatcastersWeb.Endpoint.instrument/4
(phoenix) lib/phoenix/router.ex:278: Phoenix.Router.__call__/1
(statcasters) lib/statcasters_web/endpoint.ex:1: StatcastersWeb.Endpoint.plug_builder_call/2
(statcasters) lib/plug/debugger.ex:99: StatcastersWeb.Endpoint."call (overridable 3)"/2
(statcasters) lib/statcasters_web/endpoint.ex:1: StatcastersWeb.Endpoint.call/2
(plug) lib/plug/adapters/cowboy/handler.ex:15: Plug.Adapters.Cowboy.Handler.upgrade/4
(cowboy) /Users/cameronbass/Desktop/Play/statcasters/deps/cowboy/src/cowboy_protocol.erl:442: :cowboy_protocol.execute/4
这也不像“长生不老药之路”,有人能帮我解开吗?
Ecto.Changeset.cast/4
返回Ecto.Changeset
以及此后Ecto.Changeset
所有函数,例如validate
。 您的one_team_per_user_for_leagues/1
也应遵循以下规则:
defp one_team_per_user_for_leagues(%Ecto.Changeset{} = changes) do
...
end
另一个小问题是如何将任何错误通知Ecto
:通过在Ecto.Changeset
结构中返回非空errors
值来完成:
defp one_team_per_user_for_leagues(%Ecto.Changeset{} = changes) do
case get_or_create_teams_in_this_league() do # to implement
{:existing, %Team{}} ->
new_errors = ...
%{changes | errors: new_errors ++ changes.errors, valid?: false}
{:new, %Team{}} ->
changes
|> put_assoc(:team, ...)
end
end
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.