【问题标题】:Ecto filter empty recordEcto 过滤空记录
【发布时间】:2017-04-29 20:00:44
【问题描述】:

我有两个模型用户和地址的嵌入式关联,我将它们连接起来是这样的:

defmodule App.Address do
  # ...

  def changeset(struct, params \\ %{}) do
    struct
    |> cast(params, [:address, :city])
  end
end

当我使用时:

 inputs_for :addresses, [append: [App.Address{}]], fn address ->
   text_input address, :address, class: ""
 end

我输入空数据,它被保存为 nil,我希望有一个解决方案来过滤掉空数据并防止它们被保存,我想出的只是在控制器中使用 Enum.filter 变得丑陋我想:

...
filtered_addresses = Enum.filter(user_params["addresses"], fn {x, map} ->
  map.address != "" and map.city != ""
end)

user_params = Map.put(user_params, :addresses, filtered_addresses)

是否有更简洁的方式使用模型验证,或者在控制器中使用更简洁的方式?

【问题讨论】:

  • 我认为函数 cast_embed/3 应该接受一个像 :reject_if 这样的选项,类似于 rails accepts_nested_attributes_for。我已经发布了question to elixir-ecto mailing list
  • @OleksandrAvoyants 这就是:with 选项的意义所在。您指定一个变更集,如果它无效,可以拒绝它。
  • @JustinWood 如果我错了请纠正我,但我认为目前变更集无法拒绝记录。
  • 旁注José Valim uses 显式 |> Enum.reject(& &1 == "") 用于几乎相同的任务。
  • @mudasobwa 是的,这是有道理的,这是一个简洁的解决方案。

标签: elixir phoenix-framework ecto


【解决方案1】:

您将需要对变更集进行验证。类似于

def changeset(struct, params \\ %{}) do
  struct
  |> cast(params, [:address, :city])
  |> validate_required([:address, :city])
end

这将确保addresscity 列中有数据。如果没有,记录将不会被保存。

您可以阅读有关验证和约束的更多信息in the docs

【讨论】:

  • 感谢贾斯汀的回答,地址不是必须的。未设置地址字段时,不会将任何内容保存到数据库中,不会引发错误。
  • 这不会引发错误,除非您使用的是insert!/2。如果您使用insert/2,它将返回{:ok, struct}{:error, changeset}。什么都没有引发,它只是返回一个值,你可以用它做你想做的事。
  • 是的,但它仍然要验证用户模型,所以它需要能够捕获该模型(用户)的错误
【解决方案2】:

如果我正确理解了这个问题,您可能正在寻找Phoenix.Controller.scrub_params/2

来自上面链接的文档:

此函数可用于删除通过 HTML 表单发送的空字符串。

另外,this SO question 似乎与您的问题相似,但目标恰恰相反。为了超文本,在这里链接它。

【讨论】:

  • 这不会导致nil被放入数据库吗?
  • 感谢您的回答,贾斯汀是对的,在这种情况下,scrub_params 只会检查“地址”键是否存在,而不是验证地址映射(其中包含:地址和:城市)
  • 我的印象是 Ecto 默认不会将 nils 保存到数据库中,而空字符串会。
猜你喜欢
  • 2018-04-26
  • 1970-01-01
  • 2011-08-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-18
  • 2017-08-18
  • 2015-02-13
相关资源
最近更新 更多