【问题标题】:Ecto Changeset - association not casted, if no input is givenEcto Changeset - 如果没有给出输入,则未强制转换关联
【发布时间】:2018-05-06 18:25:30
【问题描述】:

我有一个用户架构

  schema "users" do
    field :name, :string
    field :username, :string
    has_one :user_role, UserRole
  end

  def changeset(%User{} = user, attrs) do
    user
    |> cast(attrs, [:name, :username])
    |> validate_required([:name, :username])
    |> unique_constraint(:username)
  end

和 UserRole 架构

  schema "userroles" do
    field :is_admin, :boolean, default: false
    belongs_to :user, User
  end

  def changeset(%UserRole{} = user_role, attrs) do
    user_role
    |> cast(attrs, [:is_admin, :user_id])
    |> validate_required([:is_admin])
  end

它们都在同一个上下文“帐户”中,我在其中进行关联。

      #accounts.ex      
      def create_user(attrs \\ %{}) do
        %User{}
        |> User.changeset(attrs)
        |> Ecto.Changeset.cast_assoc(:user_role, required: true)
        |> Repo.insert()
      end

这是 UserController 的新建和创建:

  def new(conn, _params) do
    changeset = Accounts.change_user(%User{})
    render(conn, "new.html", changeset: changeset)
  end

  def create(conn, %{"user" => user_params}) do
    case Accounts.create_user(user_params) do
      {:ok, user} ->
        conn
        |> put_flash(:info, "User created successfully.")
        |> redirect(to: user_path(conn, :show, user))
      {:error, %Ecto.Changeset{} = changeset} ->
        render(conn, "new.html", changeset: changeset)
    end
  end

我有一个 User 和 UserRole 的嵌套表单。如果我输入所有数据,一切都会按预期进行。现在,我想隐藏 UserRole 的输入,因为我不希望用户将自己设置为“is_admin”(但如果您是管理员,您应该能够创建其他管理员帐户)。因此,如果您是非管理员用户,则不再需要输入 UserRole。我的期望是

  1. 如果没有输入,则将插入来自 UserRole 架构的默认值或
  2. UserRole 变更集中的验证表明没有输入,但它是必需的。

发生的情况是:用户已创建,但关联的 user_role 为“nil”。我不明白为什么会这样。谁能给我解释一下?

我的解决方案是:我没有给用户一个布尔值 :is_admin 的复选框,而是发送一个隐藏输入,将其设置为 false,但这似乎不是好方法。

【问题讨论】:

  • 补充:在 UserController 的 create 动作中,甚至没有在 user_params 中插入 :user_role 键。我删除了表单中的隐藏输入,现在我正在检查 user_params 中的 :user_role 键。如果没有,我创建一个新的 %UserRole{is_admin: false} 变更集并使用 put_assoc 插入它。这行得通,但我不明白为什么这是必要的,或者更确切地说,为什么没有使用默认值“false”插入 :user_role。

标签: elixir phoenix-framework


【解决方案1】:

你可以随时使用

Map.put_new(map, key, value) 在这种情况下

之前

case Accounts.create_user(user_params) do

使用params = Map.put_new(user_params, :user_role, "anything")

这将做的是,如果它在地图中找到:user_role,它将使用相同的,如果它没有找到任何东西,它将使用您指定的值。

它需要user_role 的值,因为存在与之相关的关联。虽然我觉得它应该是has_many 关联,但是您的代码显示了它的has_one,因此对于每个user 条目应该有user_role 与之关联。

如果要使用has_manybelongs_to 应该在user 架构中,has_manyuser_role 架构中

【讨论】:

  • 谢谢,@Zubair 这就像一个魅力 :) 我想我误解了架构中的默认值的用途。我知道,关系应该是 has_many。我只是想先解决这个问题,但还是感谢您提及。
猜你喜欢
  • 2014-06-20
  • 1970-01-01
  • 2022-12-10
  • 1970-01-01
  • 1970-01-01
  • 2021-06-04
  • 2022-11-11
  • 1970-01-01
  • 2019-10-17
相关资源
最近更新 更多