The signed id feature introduced in #39313 can cause loading issues
since it may try to generate a key before the secret key base has
been set. To prevent this wrap the secret initialization in a lambda.
#39378 has changed to use `build_scope` in `join_scopes`, which rely on
`reflection.klass`, but `reflection.klass` is restricted for polymorphic
association, the klass for the association should be passed explicitly.
Related to #7380 and #7392.
`merge` allows to overwrite non-attribute nodes by #7392, so
`merge(..., rewhere: true)` should also have the same ability, to
migrate from the half-baked current behavior to entirely consistent new
behavior.
An error occurs when you pass a relation with SQL comments to the `or` method.
```ruby
class Post
scope :active, -> { where(active: true).annotate("active posts") }
end
Post.where("created_at > ?", Time.current.beginning_of_month)
.or(Post.active)
```
In order to work without `ArgumentError`, it changes the `or` method to ignore
SQL comments in the argument.
Ref: https://github.com/rails/rails/pull/38145#discussion_r363024376
Before #36604, `enum` and `set` columns were incorrectly dumped as a
`string` column.
If an `enum` column is defined as `foo enum('apple','orange')`, it was
dumped as `t.string :foo, limit: 6`, the `limit: 6` is seemed to
restrict invalid string longer than `'orange'`.
But now, `enum` and `set` columns are correctly dumped as `enum` and
`set` columns, the limit as longest element is no longer used.
5 years ago, I made dumping full table options at #17569, especially to
dump `ENGINE=InnoDB ROW_FORMAT=DYNAMIC` to use utf8mb4 with large key
prefix.
In that time, omitting the default engine `ENGINE=InnoDB` was not useful
since `ROW_FORMAT=DYNAMIC` always remains as long as using utf8mb4 with
large key prefix.
But now, MySQL 5.7.9 has finally changed the default row format to
DYNAMIC, utf8mb4 with large key prefix can be used without dumping the
default engine and the row format explicitly.
So now is a good time to make the default engine is omitted.
Before:
```ruby
create_table "accounts", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci", force: :cascade do |t|
end
```
After:
```ruby
create_table "accounts", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
end
```
To entirely omit `:options` option to make schema agnostic, I've added
`:charset` and `:collation` table options to exclude `CHARSET` and
`COLLATE` from `:options`.
Fixes#26209.
Closes#29472.
See also #33608, #33853, and #34742.
We've learned that `merge` causes duplicated multiple values easily, so
if we missed to deduplicate the values, it will cause weird behavior
like #38052, #39171.
I've investigated the deduplication for the values, at least that had
existed since Rails 3.0.
bed9179aa1
Aggregations with group by multiple fields was introduced at Rails 3.1,
but we missed the deduplication for the aggregation result, unlike the
generated SQL.
a5cdf0b9eb
While the investigation, I've found that `annotate` is also missed the
deduplication.
I don't suppose this weird behavior is intended for both.
So I'd like to deprecate the duplicated behavior in Rails 6.1, and will
be deduplicated all multiple values in Rails 6.2.
To migrate to Rails 6.2's behavior, use `uniq!(:group)` to deduplicate
group fields.
```ruby
accounts = Account.group(:firm_id)
# duplicated group fields, deprecated.
accounts.merge(accounts.where.not(credit_limit: nil)).sum(:credit_limit)
# => {
# [1, 1] => 50,
# [2, 2] => 60
# }
# use `uniq!(:group)` to deduplicate group fields.
accounts.merge(accounts.where.not(credit_limit: nil)).uniq!(:group).sum(:credit_limit)
# => {
# 1 => 50,
# 2 => 60
# }
```
Related to #39328, #39358.
For now, `merge` cannot override non-equality clauses, so non-equality
clauses will easily be duplicated by `merge`.
This deduplicates redundant same clauses in `merge`.
If source/through scope references other tables in where/order, we
should explicitly maintain joins in the scope, otherwise association
queries will fail with referenced unknown column.
Fixes#33525.
`reflection.scope` is not aware of all source scopes if the association
is through association.
It should use `reflection.join_scopes` for that.
Fixes#39376.
Bump an Active Record instance's lock version after updating its counter
cache. This avoids raising an unnecessary ActiveRecord::StaleObjectError
upon subsequent transactions by maintaining parity with the
corresponding database record's lock_version column.
The `index_exists?` method wasn't very specific so when we added the
`if_not_exists` to `add_index` and `if_exists` to `remove_index` there
were a few cases where behavior was unexpected.
For `add_index` if you added a named index and then added a second index
with the same columns, but a different name, that index would not get
added because `index_exists` was looking only at column named and not at
the exact index name. We fixed `add_index` by moving the `index_exists`
check below `add_index_options` and pass `name` directly to
`index_exists` if there is a `if_not_exists` option.
For `remove_index` if you added a named index and then tried to remove
it with a nil column and a explicit name the index would not get removed
because `index_exists` saw a nil column. We fixed this by only doing the
column check in `index_exists` if `column` is present.
Co-authored-by: John Crepezzi <john.crepezzi@gmail.com>
If a has_many :through association isn't found we can suggest similar associations:
```
class Author
has_many :categorizations, -> { }
has_many :categories, through: :categorizations
has_many :categorized_posts, through: :categorizations, source: :post
has_many :category_post_comments, through: :categories, source: :post_comments
has_many :nothings, through: :kateggorisatons, class_name: "Category"
end
Author.first.nothings
Could not find the association :kateggorisatons in model Author
Did you mean? categorizations
categories
categorized_posts
category_post_comments
```
`HomogeneousIn` has changed merging behavior for NOT IN clause from
before. This changes `equality?` to return true only if `type == :in` to
restore the original behavior.
Related #39236.
`relation.merge` method sometimes replaces mergee side condition, but
sometimes maintain both conditions unless `relation.rewhere` is used.
It is very hard to predict merging result whether mergee side condition
will be replaced or not.
One existing way is to use `relation.rewhere` for merger side relation,
but it is also hard to predict a relation will be used for `merge` in
advance, except one-time relation for `merge`.
To address that issue, I propose to support merging option `:rewhere`,
to allow mergee side condition to be replaced exactly.
That option will allow non-`rewhere` relation behaves as `rewhere`d
relation.
```ruby
david_and_mary = Author.where(id: david.id..mary.id)
# both conflict conditions exists
david_and_mary.merge(Author.where(id: bob)) # => []
# mergee side condition is replaced by rewhere
david_and_mary.merge(Author.rewhere(id: bob)) # => [bob]
# mergee side condition is replaced by rewhere option
david_and_mary.merge(Author.where(id: bob), rewhere: true) # => [bob]
```
If an association isn't found we can suggest matching associations:
```
Post.all.merge!(includes: :monkeys).find(6)
Association named 'monkeys' was not found on Post; perhaps you misspelled it?
Did you mean? funky_tags
comments
images
skimmers
```
Add support for finding records based on signed ids, which are tamper-proof, verified ids that can be set to expire and scoped with a purpose. This is particularly useful for things like password reset or email verification, where you want the bearer of the signed id to be able to interact with the underlying record, but usually only within a certain time period.
This also removes the `if @transaction_state&.finalized?` guard which is
harder to understand optimization introduced at #36049. The guard is
faster enough though, but removing that will make attribute access about
2% ~ 4% faster, and will make code base to ease to maintain.
`sync_with_transaction_state` was introduced at #9068 to address memory
bloat when creating lots of AR objects inside a transaction.
I've found #18638 the same design of this to address memory bloat, but
this differs from #18638 in that it will allocate one `WeakMap` object
only when explicit transaction, no extra allocation for implicit
transaction.
Executable script to reproduce memory bloat:
https://gist.github.com/kamipo/36d869fff81cf878658adc26ee38ea1bhttps://github.com/rails/rails/issues/15549#issuecomment-46035848
I can see no memory concern with this.
Co-authored-by: Arthur Neves <arthurnn@gmail.com>
#38354 is caused by #36304, to fix invalid joins order for through
associations.
Actually passing Arel joins to `joins` is not officially supported
unlike string joins, and also Arel joins could be easily converted to
string joins by `to_sql`. But I'd not intend to break existing apps
without deprecation cycle, so I've changed to mark only implicit joins
as leading joins, to maintain the original joins order for user supplied
Arel joins.
Fixes#38354.