【问题标题】:Custom validations for changeset Elixir/Phoenix变更集 Elixir/Phoenix 的自定义验证
【发布时间】:2017-12-10 13:33:57
【问题描述】:

我有一个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

这也感觉不像是“灵药之道”,谁能帮我解开这个问题?

【问题讨论】:

    标签: elixir phoenix-framework


    【解决方案1】:

    Ecto.Changeset.cast/4 返回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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-09-14
      • 1970-01-01
      • 1970-01-01
      • 2017-11-27
      • 1970-01-01
      • 1970-01-01
      • 2020-02-20
      相关资源
      最近更新 更多