This is following a recent discussion on Basecamp.
So far Rails haven't tried to preserve Marshal compatibilty of Active Record instances,
and it probably shouldn't as it isn't as controllable as other serialization formats.
However it's common to store ActiveRecord instances in Rails.cache, and when the
Marshal format changes, it causes problems during Rails upgrade. Process using the new Rails
version might not be able to deserialize the existing cache, and also older process that
weren't restarted yet my fail to load the cache entries written by newer processes.
The goal of this PR is not to freeze the Marshal format, but to have a better visibility
when it changes, so that's it's done on purpose with good reasons rather than accidentally.
Note that this only test forward compatibility (AR vN reading entries written by AR vN-1),
ideally we'd also test backward compatibility (AR vN-1 reading entries written by AR vN),
but it means installing and loading and older Active Record as part of the test suite.
Context https://github.com/rails/rails/pull/39599#discussion_r445429365.
Similar with #39611.
Actually we never said we would keep Mashal compatibility between two
versions of Rails, so we sometimes directly removed the dedicated types
in the past (e.g. f1a0fa9, #29666), but that direct removing makes cache
rotation harder.
Keeping the unused constant in new version at least during one version
will help cache rotation easier.
We had removed the dedicated `MysqlDateTime`, `MysqlJson`, and
`OID::Json` classes in the past (f1a0fa9, #29666), so legacy YAML
loading has no longer always perfectly compatiblity.
Fortunately, v2 (Rails 5.1 style) YAML doesn't contain type information
in almost all cases (unless serializing object using custom select), so
usually removing dedicated type affects to legacy YAML older than v1
(Rails 5.0 style) YAML only.
This restores legacy YAML compatibility for MySQL with v1 format by
adding the class alias in YAML for `MysqlString` which is most recently
reported about compatibility concern. It also affects to legacy Rails
4.2 style YAML, but 4.2 style YAML had already broken by removing
`MysqlDateTime` over 4 years ago.
A relation has a predicate builder, so if a predicate handler which is
referenced by a legacy predicate builder is removed in the new code,
`Marshal.load(legacy_relation.dump)` will fail due to referencing
undefined constant.
I've restored no-op `BaseHandler` constant alias to make cache rotation
easier during Rails 6.1.
Fixes#39601.
Rails has a number of places where a YAML configuration file is read,
then ERB is evaluated and finally the YAML is parsed.
This consolidates that into one common class.
Co-authored-by: Kasper Timm Hansen <kaspth@gmail.com>
Calling `#remove_connection` on the handler is deprecated in favor of
`#remove_connection_pool`. This change was made to support changing the
return value from a hash to a `DatabaseConfig` object.
`#remove_connection` will be removed in 6.2.
NOTE: `#remove_connection` on `ActiveRecord::Base` will also now return
a `DatabaseConfig` object. We didn't use a deprecation here since
it's not documented that this method used to return a `Hash`.
Co-authored-by: John Crepezzi <john.crepezzi@gmail.com>
This method in test has a confusing name that also is the same as a
method with a different behavior on `ActiveRecord::Base` so we're just
renaming it to avoid confusion between the two!
Co-authored-by: eileencodes <eileencodes@gmail.com>
When I wrote the `connected_to` and `connects_to` API's I wrote them
with the idea in mind that it didn't really matter what the
handlers/roles were called as long as those connecting to the roles knew
which one wrote and which one read.
With the introduction of the middleware Rails begins to assume it's
`writing` and `reading` and there's no room for other roles. At GitHub
we've been using this method for a long time so we have a ton of legacy
code that uses different handler names `default` and `readonly`. We
could rename all our code but I think this is better for a few reasons:
- Legacy apps that have been using multiple databases for a long time
can have an eaiser time switching.
- If we later find this to cause more issues than it's worth we can
easily deprecate.
- We won't force old apps to rewrite the resolver middleware just to use
a different handler.
Adding the writing_role/reading_role required that I move the code that
creates the first handler for writing to the railtie. If I didn't move
this the core class would assign the handler before I was able to assign
a new one in my configuration and I'd end up with 3 handlers instead of
2.
- The query needs to be executed for hitting `select_all` so made sure
that query gets executed.
- Also instead of changing instance variable, just add new
configuration for prepared_statements: false and use it for this
test.
- This way we don't have to touch the internals of AR code and still
disable prepared statements config for this test.
Reported on #21509, how views is treated by `#tables` are differ
by each adapters. To fix this different behavior, after Rails 5.0
is released, deprecate `#tables`.
And `#table_exists?` would check both tables and views.
To make their behavior consistent with `#tables`, after Rails 5.0
is released, deprecate `#table_exists?`.
As of Ruby 2.2, Psych can handle any object which is marshallable. This
was not true on previous versions of Ruby, so our delegator types had to
provide their own implementation of `init_with` and `encode_with`.
Unfortunately, this doesn't match up with what Psych will do today.
Since by the time we hit this layer, the objects will have already been
created, I think it makes the most sense to just grab the current type
from the class.
Creating and dropping similar tables within the same connection causes postgresql to look up old values in the cache of tables which have already been dropped.
In the end I think the pain of implementing this seamlessly was not
worth the gain provided.
The intention was that it would allow plain ruby objects that might not
live in your main application to be subclassed and have persistence
mixed in. But I've decided that the benefit of doing that is not worth
the amount of complexity that the implementation introduced.
This reverts commit 98043c689f.
Because if every time `debug.log` is truncated,
developers have no way to see the previous ActiveRecord unit test results.
`debug.log` file can be easily reduced
by executing `$ touch /dev/null > debug.log` periodically.
Method compilation provides better performance and I think the code
comes out cleaner as well.
A knock on effect is that methods that get redefined produce warnings. I
think this is a good thing. I had to deal with a bunch of warnings
coming from our tests, though.