Commit Graph

129 Commits

Author SHA1 Message Date
Will Jessop
d110b7b877
Serialize symbols to strings in ImmutableString serialize method
Symbols serialize to strings when persisted:

    model.some_string = :foo
    model.save! # "foo" is persisted

This PR updates the immutable string class to serialize symbols to strings to mirror this behavior as ActiveModel::Attribute calls this serialize method to determine the return value for changed_in_place? Prior to this change this code would report that "something" had changed:

    comment = Comment.create! # (has a string "something" field)
    comment.update_column :something, :anything # persists "anything" to the "something" field of the comments table
    comment.something  # or comment.attributes
    comment.something_change # will be ["anything", "anything"], note these are `to` and `from` values, but are identical

After this PR the comment.something_change will return nil for this situation.

Fixes #36463
2019-08-10 23:37:37 +01:00
Yasuo Honda
20772f6c53 Address DEPRECATED: Use assert_nil if expecting nil
```ruby
$ cd activerecord
$ bin/test test/cases/dirty_test.rb:494
... snip ...
DEPRECATED: Use assert_nil if expecting nil from /home/yahonda/git/rails/activerecord/test/cases/dirty_test.rb:494. This will fail in Minitest 6.
DEPRECATED: Use assert_nil if expecting nil from /home/yahonda/git/rails/activerecord/test/cases/dirty_test.rb:511. This will fail in Minitest 6.
.

Finished in 0.061593s, 16.2356 runs/s, 795.5428 assertions/s.
1 runs, 49 assertions, 0 failures, 0 errors, 0 skips
$
```

Refer seattlerb/minitest#666 rails/rails#27712
2019-08-03 02:27:56 +00:00
David Heinemeier Hansson
a0bb19fbfa
Add *_previously_was attribute methods when dirty tracking (#36836) 2019-08-01 15:38:03 -07:00
Ryuta Kamizono
1d8fad6f90 Ensure update_all series cares about optimistic locking
Incrementing the lock version invalidates any other process's optimistic
lock, which is the desired outcome: the record no longer looks the same
as it did when they loaded it.
2019-02-25 20:14:56 +09:00
Ryuta Kamizono
811be47778 Use assert_no_queries not to ignore BEGIN/COMMIT queries
`test_update_does_not_run_sql_if_record_has_not_changed` would pass
without #18501 since `assert_queries` ignores BEGIN/COMMIT unless
`ignore_none: true` is given.

Since #32647, empty BEGIN/COMMIT is ommited. So we no longer need to use
`assert_queries(0)` to ignore BEGIN/COMMIT in the queries.
2018-10-05 04:11:13 +09:00
yuuji.yaginuma
12fadea8ae Remove redundant travel_back
Since #29860, `travel_back` automatically called at the end of the test.
2018-08-31 16:19:58 +09:00
Yuya Tanaka
34f075fe56 Mutation tracker should be cleared before continuing around callbacks
`changes_applied` should be called before continuing around callback
chain. Otherwise the mutation tracker returns old value for methods like
`changed`? or `id_in_database` in around callbacks. Also methods depend
on `id_in_database`, like `update_column`, are not working in
`around_create` callbacks.

```
class Foo < ActiveRecord::Base
  around_create :around_create_callback

  def around_create_callback
    ...
    yield
    p id_in_database # => nil
    update_column(:generated_column, generate_value) # silently fails
  end

  ...
end
```
2018-08-28 16:32:23 +09:00
Daniel Colson
a1ac18671a Replace assert ! with assert_not
This autocorrects the violations after adding a custom cop in
3305c78dcd.
2018-04-19 08:11:33 -04:00
Eugene Kenny
80a09caedc Prevent changes_to_save from mutating attributes
When an array of hashes is added to a `HashWithIndifferentAccess`, the
hashes are replaced with HWIAs by mutating the array in place.

If an attribute's value is an array of hashes, `changes_to_save` will
convert it to an array of HWIAs as a side-effect of adding it to the
changes hash.

Using `merge!` instead of `[]=` fixes the problem, as `merge!` copies
any array values in the provided hash instead of mutating them.
2018-04-08 23:06:48 +01:00
bogdanvlviv
61a7630891
Use with_partial_writes helper in activerecord/test/cases/dirty_test.rb
Related to 948b931925febac3c965ab13470065ced68f7b53
2018-02-28 00:32:46 +02:00
Sean Griffin
c2a2b84d8d Ensure we don't write virtual attributes on update, too
See 948b931925febac3c965ab13470065ced68f7b53 for context
2018-02-26 11:25:45 -07:00
Sean Griffin
948b931925 Never attempt to write virtual attributes to the database
Currently the place where we limit what gets sent to the database is in
the implementation for `partial_writes`. We should also be restricting
it to column names when partial writes are turned off.

Note that we're using `&` instead of just defaulting to
`self.class.column_names`, as the instance version of `attribute_names`
does not include attributes which are uninitialized (were not included
in the select clause)
2018-02-26 11:21:03 -07:00
Daniel Colson
94333a4c31 Use assert_predicate and assert_not_predicate 2018-01-25 23:32:59 -05:00
Daniel Colson
211adb47e7 Change refute to assert_not 2018-01-25 23:32:58 -05:00
Ryuta Kamizono
a954e1e817 Merge pull request #29018 from willbryant/missing_attributes_after_save
fix the dirty tracking code's save hook overwriting missing attribute…
2018-01-03 05:14:18 +09:00
bogdanvlviv
c78b672beb
Fix random CI failure DirtyTest:
```
rails/activerecord$ bundle exec rake postgresql:test TESTOPTS="--seed=26536"

..(compressed)....F

Failure:
DirtyTest#test_save_should_not_save_serialized_attribute_with_partial_writes_if_not_present [/home/travis/build/rails/rails/activerecord/test/cases/dirty_test.rb:473]:
Expected nil to not be nil.
```
2017-08-09 22:06:49 +03:00
Kir Shatrov
831be98f9a Use frozen-string-literal in ActiveRecord 2017-07-19 22:27:07 +03:00
Ryuta Kamizono
b623a62c7f Fix typo s/rause/raise/ 2017-07-19 00:08:00 +09:00
Sean Griffin
c0d8f58775 Remove deprecated code concerning non-attributes and *_will_change! 2017-07-18 10:37:31 -04:00
Sean Griffin
020abadf04 Remove deprecated code concerning dirty methods in after callbacks 2017-07-18 10:33:53 -04:00
Matthew Draper
87b3e226d6 Revert "Merge pull request #29540 from kirs/rubocop-frozen-string"
This reverts commit 3420a14590c0e6915d8b6c242887f74adb4120f9, reversing
changes made to afb66a5a598ce4ac74ad84b125a5abf046dcf5aa.
2017-07-02 02:15:17 +09:30
Kir Shatrov
cfade1ec7e Enforce frozen string in Rubocop 2017-07-01 02:11:03 +03:00
Rafael França
908b136cf2 Merge pull request #26634 from kamipo/extract_numeric_data
Extract `NumericData` model for tests
2017-05-31 15:50:08 -04:00
Will Bryant
ba2190b3b6 fix the dirty tracking code's save hook overwriting missing attributes with initialized-to-nil attributes. fixes #29017. 2017-05-10 11:23:33 +12:00
Aaron Patterson
83d6cc4815
Move around AR::Dirty and fix _attribute method
We already have a _read_attribute method that can get the value we need
from the model.  Lets define that method in AM::Dirty and use the
existing one from AR::Dirty rather than introducing a new method.
2017-04-14 10:53:47 -07:00
bogdanvlviv
b5eb3215a6 Fix inconsistency with changed attributes when overriding AR attribute reader 2017-04-12 08:06:13 +03:00
bogdanvlviv
5a072ba317 Remove ability update locking_column value 2017-03-16 10:42:33 +02:00
Ryuta Kamizono
322a4a1310 Deprecate supports_migrations? on connection adapters
`supports_migrations?` was added at 4160b518 to determine if schema
statements (`create_table`, `drop_table`, etc) are implemented in the
adapter. But all tested databases has been supported migrations since
a4fc93c3 at least.
2017-02-27 03:14:33 +09:00
Andrew White
de24b8cb9c Fix schema leakage from dirty_test.rb
The column information for the testings table was being cached
so clear the cache in the test teardown.
2017-02-21 17:04:49 +00:00
Sean Griffin
4fed08fa78 Deprecate calling attr_will_change! with non-attributes
This was never really intended to work (at least not without calling
`define_attribute_methods`, which is less common with Active Record). As
we move forward the intention is to require the use of `attribute` over
`attr_accessor` for more complex model behavior both on Active Record
and Active Model, so this behavior is deprecated.

Fixes #27956.
Close #27963.

[Alex Serban & Sean Griffin]
2017-02-11 17:46:28 -05:00
Sean Griffin
16ae3db5a5 Deprecate the behavior of AR::Dirty inside of after_(create|update|save) callbacks
We pretty frequently get bug reports that "dirty is broken inside of
after callbacks". Intuitively they are correct. You'd expect
`Model.after_save { puts changed? }; model.save` to do the same thing as
`model.save; puts model.changed?`, but it does not.

However, changing this goes much farther than just making the behavior
more intuitive. There are a _ton_ of places inside of AR that can be
drastically simplified with this change. Specifically, autosave
associations, timestamps, touch, counter cache, and just about anything
else in AR that works with callbacks have code to try to avoid "double
save" bugs which we will be able to flat out remove with this change.

We introduce two new sets of methods, both with names that are meant to
be more explicit than dirty. The first set maintains the old behavior,
and their names are meant to center that they are about changes that
occurred during the save that just happened. They are equivalent to
`previous_changes` when called outside of after callbacks, or once the
deprecation cycle moves.

The second set is the new behavior. Their names imply that they are
talking about changes from the database representation. The fact that
this is what we really care about became clear when looking at
`BelongsTo.touch_record` when tests were failing. I'm unsure that this
set of methods should be in the public API. Outside of after callbacks,
they are equivalent to the existing methods on dirty.

Dirty itself is not deprecated, nor are the methods inside of it. They
will only emit the warning when called inside of after callbacks. The
scope of this breakage is pretty large, but the migration path is
simple. Given how much this can improve our codebase, and considering
that it makes our API more intuitive, I think it's worth doing.
2016-11-01 13:16:33 -04:00
bogdanvlviv
a60a20bb7f Added ability update locking_column value 2016-10-21 19:06:02 +03:00
Ryuta Kamizono
c13dc0f825 Extract NumericData model for tests
Currently `NumericData` model is defined some places.
2016-09-27 07:24:06 +09:00
Michael Grosser
a9aed2ac94
improve error message when include assertions fail
assert [1, 3].includes?(2) fails with unhelpful "Asserting failed" message

assert_includes [1, 3], 2 fails with "Expected [1, 3] to include 2" which makes it easier to debug and more obvious what went wrong
2016-09-16 12:03:37 -07:00
Rafael Mendonça França
55f9b8129a
Add three new rubocop rules
Style/SpaceBeforeBlockBraces
Style/SpaceInsideBlockBraces
Style/SpaceInsideHashLiteralBraces

Fix all violations in the repository.
2016-08-16 04:30:11 -03:00
Ryuta Kamizono
762e3f05f3 Add Style/EmptyLines in .rubocop.yml and remove extra empty lines 2016-08-07 17:50:59 +09:00
Xavier Noria
d22e522179 modernizes hash syntax in activerecord 2016-08-06 19:37:57 +02:00
Xavier Noria
9617db2078 applies new string literal convention in activerecord/test
The current code base is not uniform. After some discussion,
we have chosen to go with double quotes by default.
2016-08-06 18:26:53 +02:00
Xavier Noria
99cf755800 systematic revision of =~ usage in AR
Where appropriatei, prefer the more concise Regexp#match?,
String#include?, String#start_with?, or String#end_with?
2016-07-23 20:22:20 +02:00
Sean Griffin
d65320714e Remove dead code from tests
This code was added in 81286f858770e0b95e15af37f19156b044ec6a95, but was
not used by that commit and does not appear to have ever been used.
2016-06-09 11:19:41 -04:00
Sean Griffin
c587b63664 Ensure that records with unselected fields can be updated
As part of refactoring mutation detection to be more performant, we
introduced the concept of `original_value` to `Attribute`. This was not
overridden in `Attribute::Uninitialized` however, so assigning ot an
uninitialized value and calling `.changed?` would raise
`NotImplementedError`.

We are using a sentinel value rather than checking the result of
`original_attribute.initialized?` in `changed?` because `original_value`
might go through more than one node in the tree.

Fixes #25228
2016-06-02 11:34:48 -04:00
Sen-Zhang
051d859880 prevent 'attribute_changed?' from returning nil 2016-04-11 19:33:52 -07:00
Sean Griffin
bff28bab29 Don't assert fractional seconds can be applied on unsupported adapters
This was passing prior to 20b177b78ef5d21c8cc255f0376f6b2e948de234,
because we were not properly applying our contract that
`model.attr == model.tap(&:save).reload.attr` for this case. Now that
that has been resolved, this test is invalid on some adapters
2015-09-24 15:27:59 -06:00
Sean Griffin
370ef3e8bb Remove debug statements
They didn't help.
2015-09-24 15:02:47 -06:00
Sean Griffin
bd6bea0f19 Add a few debug statements to figure out the build failure
Nobody can replicate locally and the failure makes no sense
2015-09-24 14:53:00 -06:00
Sean Griffin
05436172db Don't rely on subsecond precision being applied in tests
When I originally reviewed the #20317, I believe these changes were
present, but it appears that it was later updated so that they were
removed. Since Travis hadn't re-run the build, this slipped through.
2015-09-23 09:33:43 -06:00
Sean Griffin
07b4078eb6 Don't crash when mutating attributes in a getter
If a getter has side effects on the DB, `changes_applied` will be called
twice. The second time will try and remove the changed attributes cache,
and will crash because it's already been unset. This also demonstrates
that we shouldn't assume that calling getters won't change the value of
`changed_attributes`, and we need to clear the cache if an attribute is
modified.

Fixes #20531.
2015-06-12 11:03:12 -06:00
Sean Griffin
2f9d88954c Persist user provided default values, even if unchanged
This is a usability change to fix a quirk from our definition of partial
writes. By default, we only persist changed attributes. When creating a
new record, this is assumed that the default values came from the
database. However, if the user provided a default, it will not be
persisted, since we didn't see it as "changed". Since this is a very
specific case, I wanted to isolate it with the other quirks that come
from user provided default values. The number of edge cases which are
presenting themselves are starting to make me wonder if we should just
remove the ability to assign a default, in favor of overriding
`initialize`. For the time being, this is required for the attributes
API to not have confusing behavior.

We had to delete one test, since this actually changes the meaning of
`.changed?` on Active Record models. It now specifically means
`changed_from_database?`. While I think this will make the attributes
API more ergonomic to use, it is a subtle change in definition (though
not a backwards incompatible one). We should probably figure out the
right place to document this. (Feel free to open a PR doing that if
you're reading this).

/cc @rafaelfranca @kirs @senny

This is an alternate implementation of #19921.

Close #19921.

[Sean Griffin & Kir Shatrov]
2015-05-28 16:40:26 -06:00
Sean Griffin
ad127d8836 Rm Type#type_cast
This helper no longer makes sense as a separate method. Instead I'll
just have `deserialize` call `cast` by default. This led to a random
infinite loop in the `JSON` pg type, when it called `super` from
`deserialize`. Not really a great way to fix that other than not calling
super, or continuing to have the separate method, which makes the public
API differ from what we say it is.
2015-02-17 14:07:45 -07:00
Sean Griffin
1455c4c22f type_cast_for_database -> serialize 2015-02-17 13:35:23 -07:00