修改变更集中的第一个相关记录

时间:2018-06-17 18:56:06

标签: elixir phoenix-framework ecto

有没有办法通过变更集只更改关系中的第一项?阿卡,如果我有:

  • 1 account N emails

可以做类似的事情:

schema "accounts" do 
    ...
    has_many(:emails, StockrtApi.Accounts.Email)
end

def changeset(account, params) do
    account
    ...
    |> cast_assoc(:emails, required: true, with: &Email.changeset(&1, &2))
    |> put_change(first_email_only, {primary: true}) # <- might have to go in email schema
end

或者解决此类问题的最佳方法是什么?

1 个答案:

答案 0 :(得分:1)

在处理数据库时,不应该依赖任何顺序(除非显示明确的ORDER BY子句。)虽然大多数数据库驱动程序将返回没有明确ORDER BY子句的可预测的有序集, 绝不保证。也就是说,总是更喜欢表达而非隐含:只是引入另一个through关联:

schema "accounts" do 
  ...
  has_many :emails, StockrtApi.Accounts.Email
  has_one :primary_email, through: [:primary_email, :email]
end

并将此关联与通常Ecto.Changeset.put_assoc/4

联系起来

根据评论,当您需要确保有电子邮件时,请执行以下操作:

defp ensure_email(
  %Ecto.Changeset{errors: errors, changes: %{emails: emails}} = changes
) do
  case emails do  
    [] ->
      new_errors = [{:emails, {"can’t be empty", [validation: :emails]}}]
      %{changes | errors: new_errors ++ errors, valid?: false}
    _ -> changes
  end
end

并明确使用它:

def changeset(account, params) do
  account
  ...
  |> cast_assoc(:emails, required: true, with: &Email.changeset(&1, &2))
  |> ensure_email()
end

这样您就可以确保至少有一封电子邮件 - 只需将第一封电子邮件用作primary