New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve Ecto.InvalidChangesetError message for embeds #1796
Improve Ecto.InvalidChangesetError message for embeds #1796
Conversation
Hello, @wojtekmach! This is your first Pull Request that will be reviewed by Ebert, an automatic Code Review service. It will leave comments on this diff with potential issues and style violations found in the code as you push new commits. You can also see all the issues found on this Pull Request on its review page. Please check our documentation for more information. |
My only problem with this is that the values we show here are different from the fields in the changeset itself. I worry that this could be confusing. Maybe we should somehow make it more obvious that it's not what is actually stored in the changeset as the data, but rather it's logical value/interpretation. |
It's a bit redundant to include "Changeset". What about removing it from each heading like this:
This way I think it will also be less associated with the exact changeset fields. Do you think that helps @michalmuskala? |
@michalmuskala @wojtekmach how should we proceed here then? :) |
@michalmuskala ping :) I like @ericmj proposal the most, I also provided an alternative (that would be my 2nd choice) |
I think I like the solution with printing the whole changeset too. It might be helpful in some occasions to see the whole, unprocessed data, that we show currently. |
In those cases it is easy to inspect the changeset. I think in the majority of cases the changeset is not interesting. |
Yeah, that's true. I'm still worried that printing something under |
@michalmuskala that's a good point. The changeset may also have important information, such as which action is going to be used. Maybe what we could do to improve this is by adding |
@josevalim @ericmj @michalmuskala wdyt about the following? (I've added a commit) The top level changeset.action was always displayed in the first sentence of the error, but for embedded changesets I can see how it could be useful to see the actions at the bottom: |
Not sure about this but could use :erlang.error/2 to put the changeset in
the stacktrace.
…On Friday, 25 November 2016, Wojtek Mach ***@***.***> wrote:
@josevalim <https://github.com/josevalim> @ericmj
<https://github.com/ericmj> @michalmuskala
<https://github.com/michalmuskala> wdyt about the following (I've added a
commit)? The top level changeset.action was always displayed in the first
sentence of the error, but for embedded changesets I can see how it could
be useful to see the actions at the bottom:
[image: zrzut ekranu 2016-11-25 o 10 11 29]
<https://cloud.githubusercontent.com/assets/76071/20620058/06780b7e-b2f8-11e6-8d07-3e707a1d78a0.png>
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#1796 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AB6JTZZYrXnvQBhjCCESkM9RO2VCaWdjks5rBqefgaJpZM4Kwqrz>
.
|
@wojtekmach I meant to call it with the InvalidChangesetError exception as first argument, not the message. Like :erlang.error(Ecto.InvalidChangesetError.exception(...), [changeset]) |
ugh, doh. let me double check. (edit) @fishcakez thanks, I've updated the screenshot above. Personally, I find the changeset being part of exception message (and be pretty printed) to be more readable |
hey everyone, just checking-in (sorry for nagging!): we clearly have a few different ways to display this as shown in the screenshots above, is there one way we could all agree on? Personally I think I like the 2nd screenshot from the top the most (pretty printing data and changeset), but I think any of the ones shown above would be an improvement over the original message. |
I agree with @wojtekmach, I prefer the 2nd screenshot. |
I am ok with the second screenshot as long as we call the first entry "Applied changes" or something similar. |
|> Enum.map_join("\n", &" " <> &1) | ||
end | ||
|
||
defp extract_changes(%Ecto.Changeset{changes: changes}) do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the changeset is marked as action: :delete
, should we maybe remove it from showing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sounds good 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@josevalim do you mean the "main" changeset is marked as delete or one of the embeds changesets? If the main changeset is marked as delete, do you mean that we wouldn't show the last part:
** (Ecto.InvalidChangesetError) could not perform delete because changeset is invalid.
Applied changes
%{posts: [nil, %{}, %{title: "new"}, %{title: nil}, %{title: "new name"}]}
Params
%{"posts" => [%{"title" => "new"}, %{"id" => "2", "title" => nil},
%{"id" => "3", "title" => "new name"}]}
Errors
%{posts: [%{}, %{}, %{},
%{title: [{"can't be blank", [validation: :required]}]}, %{}]}
(Changeset used to be here)
or hide "Applied changes" section or something else?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem is that, when we hide the changeset, we can no longer know if the changeset is going to be inserted/updated/deleted. This way, if something was meant to be deleted but we still include it, it can be confusing. So I thought we should hide the changes not for the main changeset but any of the children changeset that is marked as delete.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@josevalim okay thanks for clarifying it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed in ebdf13c
I'm fine with going with any of the proposed solutions. They are all better from what we have right now. |
end) | ||
end | ||
defp extract_changes([%Ecto.Changeset{action: :delete} | tail]), | ||
do: [extract_changes(tail)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This shouldn't be wrapped in a list.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good catch, fixed
❤️ 💚 💙 💛 💜 |
Discussed on ML: https://groups.google.com/forum/#!topic/elixir-ecto/dB8Iu02YQO4
Before:
After:
(see an included temporary test that generates this message)
Note: I've initially used
traverse_error/2
to showcase deeply nested changesets. Problem with just using traverse_error that is we'd lose distinction betweenchangeset.errors
andchangeset.changes.foo.errors
which may or may not be a good thing. Alternatively, something close to what was originally proposed on ML could be used, e.g.: (not sure about the exact format)