the strings true and false into boolean types, in order to match how
YAML would parse the same values from database.yml and prevent
unexpected type errors in the database adapters.
This caused a bug with the new associations implementation, because now
association conditions are represented as Arel nodes internally right up
to when the whole thing gets turned to SQL.
In Rails 3.2, association conditions get turned to raw SQL early on,
which prevents Relation#merge from interfering.
The current implementation was buggy when a default_scope existed on the
target model, since we would basically end up doing:
default_scope.merge(association_scope)
If default_scope contained a where(foo: 'a') and association_scope
contained a where(foo: 'b').where(foo: 'c') then the merger would see
that the same column is representated on both sides of the merge and
collapse the wheres to all but the last: where(foo: 'c')
Now, the RHS of the merge is left alone.
Fixes#8990
Previously, when `time_zone_aware_attributes` were enabled, after
changing a datetime or timestamp attribute and then changing it back
to the original value, `changed_attributes` still tracked the
attribute as changed. This caused `[attribute]_changed?` and
`changed?` methods to return true incorrectly.
Example:
in_time_zone 'Paris' do
order = Order.new
original_time = Time.local(2012, 10, 10)
order.shipped_at = original_time
order.save
order.changed? # => false
# changing value
order.shipped_at = Time.local(2013, 1, 1)
order.changed? # => true
# reverting to original value
order.shipped_at = original_time
order.changed? # => false, used to return true
end
Also covers any non-castable case by returning nil, which
is in-line with the intention of the former implementation,
but covers the odd cases which respond to to_i but raise
an error when it's called, such as NaN, Infinity and -Infinity.
Fixes#8757
This commit fixes a bug introduced in 96a13fc7 which breaks behaviour of
integer fields.
In 3.2.8, setting the value of an integer field to a non-integer (eg.
Array, Hash, etc.) would default to 1 (true) :
# 3.2.8
p = Post.new
p.category_id = [ 1, 2 ]
p.category_id # => 1
p.category_id = { 3 => 4 }
p.category_id # => 1
In 3.2.9 and above, this will raise a NoMethodError :
# 3.2.9
p = Post.new
p.category_id = [ 1, 2 ]
NoMethodError: undefined method `to_i' for [1, 2]:Array
Whilst at first blush this appear to be sensible, it combines in bad
ways with scoping.
For example, it is common to use scopes to control access to data :
@collection = Posts.where(:category_id => [ 1, 2 ])
@new_post = @collection.new
In 3.2.8, this would work as expected, creating a new Post object
(albeit with @new_post.category_id = 1). However, in 3.2.9 this will
cause the NoMethodError to be raised as above.
It is difficult to avoid triggering this error without descoping before
calling .new, breaking any apps running on 3.2.8 that rely on this
behaviour.
This patch deviates from 3.2.8 in that it does not retain the somewhat
spurious behaviour of setting the attribute to 1. Instead, it explicitly
sets these invalid values to nil :
p = Post.new
p.category_id = [ 1, 2 ]
p.category_id # => nil
This also fixes the situation where a scope using an array will
"pollute" any newly instantiated records.
@new_post = @collection.new
@new_post.category_id # => nil
Finally, 3.2.8 exhibited a behaviour where setting an object to an
integer field caused it to be coerced to "1". This has not been
retained, as it is spurious and surprising in the same way that setting
Arrays and Heshes was :
c = Category.find(6)
p = Post.new
# 3.2.8
p.category_id = c
p.category_id # => 1
# This patch
p.category_id = c
p.category_id # => nil
This commit includes explicit test cases that expose the original issue
with calling new on a scope that uses an Array. As this is a common
situation, an explicit test case is the best way to prevent regressions
in the future.
It also updates and separates existing tests to be explicit about the
situation that is being tested (eg. AR objects vs. other objects vs.
non-integers)
This issue only happens on master due to internal AR refactorings, so
there is no need for a changelog entry.
The test was backported to 3-2-stable to ensure there won't be any regressions.
Pending work on graceful app upgrades.
Revert "Merge pull request #8439 from joshsusser/fixes"
This reverts commit ce8ac39338f86388e70356b3a470b3ea443802ae, reversing
changes made to b0e7b6f67c984d4b1502e801781ed75fad681633.
Revert "Merge pull request #8431 from joshsusser/schemadump"
This reverts commit 036d3e1c2b65c4b8cbd23de2e20ad67b9b756182, reversing
changes made to 0c692f4d121792117b6a71e5ed590a31c3b9d12e.
Revert "Merge branch 'joshsusser-master' into merge"
This reverts commit 0c692f4d121792117b6a71e5ed590a31c3b9d12e, reversing
changes made to 2e299fca715b083a60222a85e48f9d3b8dd8ce93.
Conflicts:
activerecord/CHANGELOG.md
activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
activerecord/test/cases/schema_dumper_test.rb
in the new 'variables:' hash in each database config section in database.yml.
The key-value pairs of this hash will be sent in a 'SET key = value, ...'
query on new database connections.
The configure_connection methods from mysql and mysql2 into are
consolidated into the abstract_mysql base class.
The real win with these chain methods is where.not, that takes care of
different scenarios in a graceful way, for instance when the given value
is nil.
where("author.id != ?", author_to_ignore.id)
where.not("author.id", author_to_ignore.id)
Both where.like and where.not_like compared to the SQL versions doesn't
seem to give us that much:
Post.where("title LIKE 'ruby on%'")
Post.where.like(title: 'ruby on%'")
Post.where("title NOT LIKE 'ruby on%'")
Post.where.not_like(title: 'ruby on%'")
Thus Rails is adding where.not, but not where.like/not_like and others.
Relation.where with no args can be chained with not, like, and not_like
Conflicts:
activerecord/CHANGELOG.md
activerecord/lib/active_record/relation/query_methods.rb
When applying default_scope to a class with a where clause, using
update_column(s) could generate a query that would not properly update
the record due to the where clause from the default_scope being applied
to the update query.
class User < ActiveRecord::Base
default_scope where(active: true)
end
user = User.first
user.active = false
user.save!
user.update_column(:active, true) # => false
In this situation we want to skip the default_scope clause and just
update the record based on the primary key. With this change:
user.update_column(:active, true) # => true
Fixes#8436.