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
attribute_changed? returns nil (instead of false) for unchanged attributes (4.2.1) #20110
Comments
No. |
hrm, I tend to agree here - |
But still, it's an API change from 4.1 to 4.2. If that's the core team's opinion, then, OK. I'll just work around that bug (IMO this still is a bug). Thanks! |
@siebertm it's officially not an API change because the method was never documented as returning |
@matthewd Don't understand me "insisting" on being right, but when I look at the docs for ActiveModel::Dirty, at least the examples clearly document Since these dynamic methods are not documented elsewhere, I (the user) get the impression that it returns either true or false, since also the other documented methods state this, e.g.
|
Good point. |
Yeah, that is the tricky part of our policy for boolean, the code examples will be sometimes not accurate. I'd say that what we want to document there is false not In this case I'd say that our policy of using boolean semantics instead of exactly values have precedence. |
@siebertm Let me fill you in with some history! 😄 Like Matthew and the article suggested, this (whether predicate methods ending in a The decision that was made was that "No, they should only guarantee a truthy/falsy return value, i.e. anything that is not The main arguments are:
So that was why the policy was made. Now, there has been some difficulties in terms of executing said policy, mostly in "how should we document these methods". No matter what you do, it is difficult to make this history and policy obvious to the casual reader that didn't start reading the manual from page zero (which is totally understandable). What we try to do is:
Occasionally, we let these things slip into the documentation and ended up in a released version. In those cases we view that as a mistake on our part (that we accidentally promised something we shouldn't in the docs) so we change the code to return The code example case is tricky like Rafael mentioned, and I don't think we have a good way to handle that ambiguity, so it's kind of a grey area. I suppose we need to make another Executive Decision on this and how to make it more obvious going forward. For that, @fxn is probably the best person who is in the position of making that call. So I'll reopen the issue and let him decide one way or other or chime in with some more details. Once this settles, if you have other ideas to improve this in the right direction (i.e. make the docs clearer, not changing the code across the project), feel free to suggest them. I'm sure the documentation/guides could use some improvements on this topic. It'll help others avoid going down the pit you stumbled into in the future 😄 👍 |
@chancancode hat tip, awesome summary. Regarding this particular PR, in the past sometimes we've acknowledged that the code example return values could make people think singletons were guaranteed, I remember 126dc47 for example. (Please ignore the comment about YARD.) I think the only way out of this situation is to document Since Ruby does not have a The problem to implement a policy like that today is that we don't have a formal/structured/predictable way to document signatures. Our last plan with @zzak was to explore something really simple based on |
Thanks for the explanation @chancancode and @fxn! Also, to make you understand why I openend this ticket: We have a model with a boolean column and a NOT NULL constraint. In the model we call: def do_something
self.boolean_column = foo_changed? || bar_changed?
end So, when the The tests for that used to work till we upgraded to 4.2. What we came up with was either using def do_something
self.boolean_column = foo_changed? || bar_changed? || false
end |
@siebertm that's the point: when the API only guarantees boolean semantics, client code needs to get singletons if it totally needs them (rare). In code like yours, self.boolean_column = !!(foo_changed? || bar_changed?) Looks ugly eh? As Godfrey explained above that's precisely one of the reasons we don't generally commit to singletons, because we don't want those That's a client code code responsibility, because it is client code who needs to transfer types across different technologies. Like serializing a boolean value to be interpreted by JavaScript: Since JavaScript has different boolean semantics, you are responsible for ensuring the serialization is going to be interpreted correctly. (That was the start of the thread @matthewd linked above.) Returning to this issue, in the case http://api.rubyonrails.org/classes/ActiveModel/Dirty.html, there's little information but code examples. And As per a general policy, I think if the the main docs only document boolean semantics, examples of course do not override that. If we adopted that policy, then we wouldn't be able to document |
Calling `changed_attributes` will ultimately check if every mutable attribute has changed in place. Since this gets called whenever an attribute is assigned, it's extremely slow. Instead, we can avoid this calculation until we actually need it. Fixes #18029
@siebertm side note. if you slap a |
FWIW I also ran into this and found it a surprise. It was not a big fix, I had |
This issue has been automatically marked as stale because it has not been commented on for at least The resources of the Rails team are limited, and so we are asking for your help. If you can still reproduce this error on the Thank you for all your contributions. |
This issue has been automatically closed because of inactivity. If you can still reproduce this error on the Thank you for all your contributions. |
During an upgrade from 4.1 to 4.2 I noticed that
<attribute>_changed?
returnsnil
for unchanged attributes.On 4.1 and 4.0 it used to return
false
IMO (and my colleagues agreed), a "?"-method should always return a boolean.
Do you agree? If so, I'd happily attach a PR with test and fix.
The text was updated successfully, but these errors were encountered: