mathieuprog / polymorphic_embed

Polymorphic embeds in Ecto
Apache License 2.0
341 stars 63 forks source link

Allow passing more args to embedded's changesets #24

Closed icehaunter closed 3 years ago

icehaunter commented 3 years ago

Ecto's Ecto.Changeset.cast_embed/3 allows specifying the :with option, where you can not only specify which changeset to use, but also whether to pass any additional arguments. I find myself missing this function when working with nested validations dependent on some parent's data.

mathieuprog commented 3 years ago

When passing an MFA to specify which changeset to use (and which allows you to pass additional arguments), you have to specify a module. Example from the docs:

with: {Author, :special_changeset, ["hello"]} will be invoked as Author.special_changeset(changeset, params, "hello")

Because the embed is polymorphic, we would require the user to specify the custom changeset per type:

with: [author: {Author, :special_changeset, ["hello"]}, publisher: {Publisher, :special_changeset, ["hello"]}]

What do you think about that?

icehaunter commented 3 years ago

Thanks for the attention to my request!

Yeah, of course you'd need to specify the changeset separately for each type of embed, that's logical. Code will be quite verbose, but that might be a niche feature.

So yeah, your proposal works well for me

mathieuprog commented 3 years ago

I've added this feature in v1.4.0

However I did a bit differently:

changeset
|> cast_polymorphic_embed(:channel,
  with: [
    sms: {SMS, :custom_changeset, ["foo", "bar"]},
    email: &Email.custom_changeset/2
  ]
)
mathieuprog commented 3 years ago

By the way, could you briefly explain me your use case? I'm curious to know the reason to use custom changesets.

icehaunter commented 3 years ago

Awesome, thanks!

The reason for this was the need to pass through some data into the changesets to base the validation upon. For example (not for polymorphic embeds, for custom changesets), we parsed the app from the request and then allowed only some values in a validate_inclusion based on that (e.g. feature selection). There were more complex cases of course, hence the initial request.