Ecto Changeset, разрешающая виртуальную ассоциацию во время изменения, не работает - PullRequest
0 голосов
/ 05 мая 2018

Мне нужна виртуальная ассоциация, чтобы я мог создавать полиморфные ассоциации. Итак, у меня есть схема изображения, которая связана с пользователями (и другими). У меня будет место в обратном вызове, где я назначу полиморфный тип / id для схемы, но для этого нужно назначить изменения, но с этим я борюсь. В настоящее время у меня есть.

defmodule App.Picture do
  schema "pictures" do
    ...
    field :pictureable, :map, virtual: true
  end

  @attrs [:picture, :pictureable_id, :pictureable_type]

  def changeset(picture, attrs) do
    picture
    |> cast(attrs, @attrs ++ [:pictureable])
    |> handle_polymorphic
    |> cast_attachments(attrs, [:picture])
    |> validate_required(@attrs)
  end

  def handle_polymorphic(%{changes: %{pictureable: %type{id: id}}} = ch) do
    ch
    |> put_change(:pictureable_type, type)
    |> put_change(:pictureable_id, id)
  end
end

Довольно просто. Вы создаете картинку, используя атрибуты типа %{picture: Path.to("/image"), pictureable: user}, которые будут преобразованы в %{picture: Arc.stuff, pictureable_id: 1, pictureable_type: "App.User"}

Проблема с кодом выше в том, что :pictureable не сохраняется в наборе изменений

pic = %Plug.Upload{content_type: ...}
user = insert(:user)
args = %{picture: img, pictureable: user}
ch = Picture.changeset(%Picture{}, args)

Моя ревизия возвращается вот так

#Ecto.Changeset<
  action: nil,
  changes: %{
    picture: %{
      file_name: "10x10.png",
      updated_at: #Ecto.DateTime<2018-05-05 18:59:18>
    }
  },
  errors: [
    pictureable_id: {"can't be blank", [validation: :required]},
    pictureable_type: {"can't be blank", [validation: :required]},
    pictureable: {"is invalid", [type: :map, validation: :cast]}
  ],
  data: #App.Picture<>,
  valid?: false
>

Почему он не назначит карту, как ожидается, для виртуальной схемы?

РЕДАКТИРОВАТЬ: Это работает, если я использую field :pictureable, :any, virtual: true. Таким образом, кажется, что существует некоторая проблема со структурой, не являющейся картой, даже если пользователь пройдет тест is_map(user). Есть идеи, почему к нему относятся так, будто это не карта?

1 Ответ

0 голосов
/ 16 мая 2018

Моя первоначальная склонность - просто не разыгрывать изобразительное, так как вы действительно не хотите, чтобы Ecto испортил тип данных ...

def changeset(picture, attrs) do
  picture
  |> cast(attrs, @attrs ++ [:pictureable])
  |> handle_polymorphic(attrs[:picturable])
  |> cast_attachments(attrs, [:picture])
  |> validate_required(@attrs)
end

def handle_polymorphic(ch, nil), do: ch
def handle_polymorphic(ch, %type{id: id}) do
  ch
  |> put_change(:pictureable_type, type)
  |> put_change(:pictureable_id, id)
end
...