【问题标题】:Ecto validation fails with no errorEcto 验证失败且没有错误
【发布时间】:2015-03-13 07:08:30
【问题描述】:

我正在尝试创建一个基本的 CRUD 应用程序,但我遇到了验证问题。这是我的控制器操作:

def update(conn, %{"id" => id, "user" => params}) do
  case Repo.get(User, String.to_integer(id)) do
    user when is_map(user) ->
      user = Map.merge(user, atomize_keys(params))
      case User.validate(user) do
        [] ->
          Repo.update(user)
          redirect conn, to: user_path(:show, user.id)
        errors ->
          text conn, "Validation Failed!"
          ##render conn, "editform.html", user: user, errors: errors
      end
    _ ->
      redirect conn, to: user_path(:index)
  end
end

还有我的模特:

defmodule MyApp.User do
  use Ecto.Model
  validate user, 
   email: present()

  schema "users" do
   field :first_name, :string
   field :last_name, :string
   field :email, :string
   field :created_at, :datetime, default: Ecto.DateTime.local
   field :updated_at, :datetime, default: Ecto.DateTime.local
  end
end

User.validate(user) 似乎返回了一些东西,但不是错误 - form.html 中没有显示错误。我在这里想念什么?这可能是 atomize_keys() 函数的问题吗?这是那个:

defp atomize_keys(struct) do
  Enum.reduce struct, %{}, fn({k, v}, map) 
  -> Map.put(map,  String.to_atom(k), v) end
end

【问题讨论】:

  • 抱歉,我标记了它,但没有提到这是带有 Phoenix 框架的 Elixir。
  • 快速提问?您正在运行什么版本的 ecto?较新的版本 (>0.7) 使用变更集而不是验证。可能是问题的一部分...
  • 我现在在工作,这是我的家庭项目,但我确实检查了 Ecto 源代码,发现 present() 是一个函数。它也不会使编译失败,这让我认为存在“验证”宏。今晚我会检查版本 - 你能告诉我后续版本的文档方向吗?
  • 好吧,事实证明,我有一个旧版本的 Ecto。我克隆了 Ecto 9.0 和 Phoenix 0.10,在搞砸了几个小时后,无法连接到数据库。我已经在 confix.exs 中设置了我的配置,但我收到了“无效密码”消息。在终端中使用 psql 时密码有效:-/ 对新版本 ecto 有什么建议吗?

标签: elixir phoenix-framework ecto


【解决方案1】:

你的配置应该是这样的:

# config/config.exs
use Mix.Config

# Your endpoint config and your logger config go here...

# DB config:
config :my_app, MyApp.Repo,
   adapter: Ecto.Adapters.Postgres,
   database: "myapp",
   username: "username",
   password: "password",
   server: "localhost"

那么你的模型可以如下所示:

defmodule MyApp.User do
  use Ecto.Model

  schema "users" do
    field :first_name, :string
    field :last_name, :string
    field :email, :string
    field :created_at, :datetime, default: Ecto.DateTime.local
    field :updated_at, :datetime, default: Ecto.DateTime.local
  end

  def changeset(params, :create) do
    # Read the docs for Ecto.Changeset.cast, by including email in the second argument, it becomes required, the third argument are the optional arguments. Anything not in these two lists will be dropped out of the passed in params.
    # User validate_change for other custom validations.
    %User{}
    |> cast(params, ~w(email), ~(first_name last_name)
    |> validate_unique(:email, on: MyApp.Repo)
  end

  def changeset(params, :update, user) do
    user
    |> cast(params, [], ~w(email first_name last_name))
    |> validate_unique(:email, on: MyApp.Repo)
  end
end

这个模型代码的好部分意味着你的控制器可以看起来像:

def update(conn, %{"id" => id, "user" => params}) do
  user = MyApp.Repo.get(User, id)

  case user do
    %MyApp.User{} ->
      changeset = User.changeset(params, :update, user)

      if changeset.valid? do
        Repo.update(changeset)
        redirect conn, to: user_path(:show, user.id)
      else
        render conn "editform.html", user: user, errors: changeset.errors
      end
    _ ->
      redirect conn, to: user_path(:index)
  end
end

【讨论】:

  • 警告,我没有为 HTML 使用过 Phoenix 视图,所以渲染和重定向的东西可能需要仔细检查。但是控制器的其余部分应该相当可靠。
  • 我最终得到了与上述类似的东西——但配置是从 dev.exs 中提取数据库连接数据,而不是从配置中提取。此外,显然 Repo 文件现在有了一个主页,而不是与以前版本的模型一起转储。
猜你喜欢
  • 1970-01-01
  • 2011-04-21
  • 1970-01-01
  • 2012-06-19
  • 2013-01-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多