aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actioncable/lib/action_cable/connection/faye_event_loop.rb2
-rw-r--r--actionpack/CHANGELOG.md2
-rw-r--r--actionview/lib/action_view/template/types.rb1
-rw-r--r--activemodel/lib/active_model/type/decimal.rb12
-rw-r--r--activemodel/lib/active_model/validations/clusivity.rb7
-rw-r--r--activemodel/test/cases/type/decimal_test.rb7
-rw-r--r--activemodel/test/cases/validations/inclusion_validation_test.rb20
-rw-r--r--activerecord/CHANGELOG.md7
-rw-r--r--activerecord/lib/active_record/attribute/user_provided_default.rb15
-rw-r--r--activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb2
-rw-r--r--activerecord/lib/active_record/model_schema.rb12
-rw-r--r--activerecord/lib/active_record/railtie.rb1
-rw-r--r--activerecord/lib/active_record/relation.rb4
-rw-r--r--activerecord/lib/active_record/tasks/database_tasks.rb1
-rw-r--r--activerecord/test/cases/attributes_test.rb11
-rw-r--r--activerecord/test/cases/tasks/database_tasks_test.rb15
-rw-r--r--activesupport/CHANGELOG.md2
-rw-r--r--guides/source/active_record_validations.md19
18 files changed, 117 insertions, 23 deletions
diff --git a/actioncable/lib/action_cable/connection/faye_event_loop.rb b/actioncable/lib/action_cable/connection/faye_event_loop.rb
index 8b70f3d84e..9c44b38bc3 100644
--- a/actioncable/lib/action_cable/connection/faye_event_loop.rb
+++ b/actioncable/lib/action_cable/connection/faye_event_loop.rb
@@ -36,7 +36,7 @@ module ActionCable
end
def shutdown
- inner.cancel
+ @inner.cancel
end
end
end
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index e8a29f5182..97ce7ffc75 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -40,7 +40,7 @@
not meant to handle XML requests.
Third, if the current request is an "interactive" browser request (the user
- navigated here by entering the URL in the address bar, submiting a form,
+ navigated here by entering the URL in the address bar, submitting a form,
clicking on a link, etc. as opposed to an XHR or non-browser API request),
`ActionView::UnknownFormat` is raised to display a helpful error
message.
diff --git a/actionview/lib/action_view/template/types.rb b/actionview/lib/action_view/template/types.rb
index c233d06ccb..b32567cd66 100644
--- a/actionview/lib/action_view/template/types.rb
+++ b/actionview/lib/action_view/template/types.rb
@@ -1,4 +1,3 @@
-require 'set'
require 'active_support/core_ext/module/attribute_accessors'
module ActionView
diff --git a/activemodel/lib/active_model/type/decimal.rb b/activemodel/lib/active_model/type/decimal.rb
index d19d8baada..11ea327026 100644
--- a/activemodel/lib/active_model/type/decimal.rb
+++ b/activemodel/lib/active_model/type/decimal.rb
@@ -29,12 +29,12 @@ module ActiveModel
end
end
- scale ? casted_value.round(scale) : casted_value
+ apply_scale(casted_value)
end
def convert_float_to_big_decimal(value)
if precision
- BigDecimal(value, float_precision)
+ BigDecimal(apply_scale(value), float_precision)
else
value.to_d
end
@@ -47,6 +47,14 @@ module ActiveModel
precision.to_i
end
end
+
+ def apply_scale(value)
+ if scale
+ value.round(scale)
+ else
+ value
+ end
+ end
end
end
end
diff --git a/activemodel/lib/active_model/validations/clusivity.rb b/activemodel/lib/active_model/validations/clusivity.rb
index bad9e4f9a9..d49af603bb 100644
--- a/activemodel/lib/active_model/validations/clusivity.rb
+++ b/activemodel/lib/active_model/validations/clusivity.rb
@@ -30,14 +30,15 @@ module ActiveModel
@delimiter ||= options[:in] || options[:within]
end
- # In Ruby 1.9 <tt>Range#include?</tt> on non-number-or-time-ish ranges checks all
+ # In Ruby 2.2 <tt>Range#include?</tt> on non-number-or-time-ish ranges checks all
# possible values in the range for equality, which is slower but more accurate.
# <tt>Range#cover?</tt> uses the previous logic of comparing a value with the range
- # endpoints, which is fast but is only accurate on Numeric, Time, or DateTime ranges.
+ # endpoints, which is fast but is only accurate on Numeric, Time, Date,
+ # or DateTime ranges.
def inclusion_method(enumerable)
if enumerable.is_a? Range
case enumerable.first
- when Numeric, Time, DateTime
+ when Numeric, Time, DateTime, Date
:cover?
else
:include?
diff --git a/activemodel/test/cases/type/decimal_test.rb b/activemodel/test/cases/type/decimal_test.rb
index 353dbf84ad..1950566c0e 100644
--- a/activemodel/test/cases/type/decimal_test.rb
+++ b/activemodel/test/cases/type/decimal_test.rb
@@ -52,6 +52,13 @@ module ActiveModel
assert_not type.changed?(5.0, 5.0, '5.0')
assert_not type.changed?(-5.0, -5.0, '-5.0')
end
+
+ def test_scale_is_applied_before_precision_to_prevent_rounding_errors
+ type = Decimal.new(precision: 5, scale: 3)
+
+ assert_equal BigDecimal("1.250"), type.cast(1.250473853637869)
+ assert_equal BigDecimal("1.250"), type.cast("1.250473853637869")
+ end
end
end
end
diff --git a/activemodel/test/cases/validations/inclusion_validation_test.rb b/activemodel/test/cases/validations/inclusion_validation_test.rb
index 6cb96343fa..9bd44175a6 100644
--- a/activemodel/test/cases/validations/inclusion_validation_test.rb
+++ b/activemodel/test/cases/validations/inclusion_validation_test.rb
@@ -21,24 +21,38 @@ class InclusionValidationTest < ActiveModel::TestCase
end
def test_validates_inclusion_of_time_range
- Topic.validates_inclusion_of(:created_at, in: 1.year.ago..Time.now)
+ range_begin = 1.year.ago
+ range_end = Time.now
+ Topic.validates_inclusion_of(:created_at, in: range_begin..range_end)
assert Topic.new(title: 'aaa', created_at: 2.years.ago).invalid?
assert Topic.new(title: 'aaa', created_at: 3.months.ago).valid?
assert Topic.new(title: 'aaa', created_at: 37.weeks.from_now).invalid?
+ assert Topic.new(title: 'aaa', created_at: range_begin).valid?
+ assert Topic.new(title: 'aaa', created_at: range_end).valid?
end
def test_validates_inclusion_of_date_range
- Topic.validates_inclusion_of(:created_at, in: 1.year.until(Date.today)..Date.today)
+ range_begin = 1.year.until(Date.today)
+ range_end = Date.today
+ Topic.validates_inclusion_of(:created_at, in: range_begin..range_end)
assert Topic.new(title: 'aaa', created_at: 2.years.until(Date.today)).invalid?
assert Topic.new(title: 'aaa', created_at: 3.months.until(Date.today)).valid?
assert Topic.new(title: 'aaa', created_at: 37.weeks.since(Date.today)).invalid?
+ assert Topic.new(title: 'aaa', created_at: 1.year.until(Date.today)).valid?
+ assert Topic.new(title: 'aaa', created_at: Date.today).valid?
+ assert Topic.new(title: 'aaa', created_at: range_begin).valid?
+ assert Topic.new(title: 'aaa', created_at: range_end).valid?
end
def test_validates_inclusion_of_date_time_range
- Topic.validates_inclusion_of(:created_at, in: 1.year.until(DateTime.current)..DateTime.current)
+ range_begin = 1.year.until(DateTime.current)
+ range_end = DateTime.current
+ Topic.validates_inclusion_of(:created_at, in: range_begin..range_end)
assert Topic.new(title: 'aaa', created_at: 2.years.until(DateTime.current)).invalid?
assert Topic.new(title: 'aaa', created_at: 3.months.until(DateTime.current)).valid?
assert Topic.new(title: 'aaa', created_at: 37.weeks.since(DateTime.current)).invalid?
+ assert Topic.new(title: 'aaa', created_at: range_begin).valid?
+ assert Topic.new(title: 'aaa', created_at: range_end).valid?
end
def test_validates_inclusion_of
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index 3cfebdc2d0..53b669dc72 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,10 @@
+* The form builder now properly displays values when passing a proc form
+ default to the attributes API.
+
+ Fixes #24249.
+
+ *Sean Griffin*
+
* MySQL: strict mode respects other SQL modes rather than overwriting them.
Setting `strict: true` adds `STRICT_ALL_TABLES` to `sql_mode`. Setting
`strict: false` removes `STRICT_TRANS_TABLES`, `STRICT_ALL_TABLES`, and
diff --git a/activerecord/lib/active_record/attribute/user_provided_default.rb b/activerecord/lib/active_record/attribute/user_provided_default.rb
index 6dbd92ce28..4580813364 100644
--- a/activerecord/lib/active_record/attribute/user_provided_default.rb
+++ b/activerecord/lib/active_record/attribute/user_provided_default.rb
@@ -4,20 +4,25 @@ module ActiveRecord
class Attribute # :nodoc:
class UserProvidedDefault < FromUser # :nodoc:
def initialize(name, value, type, database_default)
+ @user_provided_value = value
super(name, value, type, database_default)
end
- def type_cast(value)
- if value.is_a?(Proc)
- super(value.call)
+ def value_before_type_cast
+ if user_provided_value.is_a?(Proc)
+ @memoized_value_before_type_cast ||= user_provided_value.call
else
- super
+ @user_provided_value
end
end
def with_type(type)
- self.class.new(name, value_before_type_cast, type, original_attribute)
+ self.class.new(name, user_provided_value, type, original_attribute)
end
+
+ protected
+
+ attr_reader :user_provided_value
end
end
end
diff --git a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb
index ebaaa54b2b..e160460286 100644
--- a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb
+++ b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb
@@ -104,7 +104,7 @@ module ActiveRecord
To silence this deprecation warning, add the following:
- config.active_record.time_zone_aware_types << :time
+ config.active_record.time_zone_aware_types = [:datetime, :time]
MESSAGE
end
diff --git a/activerecord/lib/active_record/model_schema.rb b/activerecord/lib/active_record/model_schema.rb
index ee52c3ae02..52eab952e1 100644
--- a/activerecord/lib/active_record/model_schema.rb
+++ b/activerecord/lib/active_record/model_schema.rb
@@ -231,6 +231,18 @@ module ActiveRecord
@explicit_sequence_name = true
end
+ # Determines if the primary key values should be selected from their
+ # corresponding sequence before the insert statement.
+ def prefetch_primary_key?
+ connection.prefetch_primary_key?(table_name)
+ end
+
+ # Returns the next value that will be used as the primary key on
+ # an insert statment.
+ def next_sequence_value
+ connection.next_sequence_value(sequence_name)
+ end
+
# Indicates whether the table associated with this class exists
def table_exists?
connection.schema_cache.data_source_exists?(table_name)
diff --git a/activerecord/lib/active_record/railtie.rb b/activerecord/lib/active_record/railtie.rb
index 4c074c93ed..98ea425d16 100644
--- a/activerecord/lib/active_record/railtie.rb
+++ b/activerecord/lib/active_record/railtie.rb
@@ -65,7 +65,6 @@ module ActiveRecord
ActiveSupport.on_load(:active_record) do
self.time_zone_aware_attributes = true
self.default_timezone = :utc
- self.time_zone_aware_types = ActiveRecord::Base.time_zone_aware_types
end
end
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index 09afdc6c69..777b593812 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -45,8 +45,8 @@ module ActiveRecord
k.name == primary_key
}]
- if !primary_key_value && connection.prefetch_primary_key?(klass.table_name)
- primary_key_value = connection.next_sequence_value(klass.sequence_name)
+ if !primary_key_value && klass.prefetch_primary_key?
+ primary_key_value = klass.next_sequence_value
values[arel_attribute(klass.primary_key)] = primary_key_value
end
end
diff --git a/activerecord/lib/active_record/tasks/database_tasks.rb b/activerecord/lib/active_record/tasks/database_tasks.rb
index 261a6a264f..8881986f1b 100644
--- a/activerecord/lib/active_record/tasks/database_tasks.rb
+++ b/activerecord/lib/active_record/tasks/database_tasks.rb
@@ -159,6 +159,7 @@ module ActiveRecord
Migrator.migrate(migrations_paths, version) do |migration|
scope.blank? || scope == migration.scope
end
+ ActiveRecord::Base.clear_cache!
ensure
Migration.verbose = verbose_was
end
diff --git a/activerecord/test/cases/attributes_test.rb b/activerecord/test/cases/attributes_test.rb
index 2991ca8b76..2bebbfa205 100644
--- a/activerecord/test/cases/attributes_test.rb
+++ b/activerecord/test/cases/attributes_test.rb
@@ -135,6 +135,17 @@ module ActiveRecord
assert_equal 2, klass.new.counter
end
+ test "procs are memoized before type casting" do
+ klass = Class.new(OverloadedType) do
+ @@counter = 0
+ attribute :counter, :integer, default: -> { @@counter += 1 }
+ end
+
+ model = klass.new
+ assert_equal 1, model.counter_before_type_cast
+ assert_equal 1, model.counter_before_type_cast
+ end
+
test "user provided defaults are persisted even if unchanged" do
model = OverloadedType.create!
diff --git a/activerecord/test/cases/tasks/database_tasks_test.rb b/activerecord/test/cases/tasks/database_tasks_test.rb
index 429aeca1d9..0aac5bad31 100644
--- a/activerecord/test/cases/tasks/database_tasks_test.rb
+++ b/activerecord/test/cases/tasks/database_tasks_test.rb
@@ -309,19 +309,30 @@ module ActiveRecord
end
class DatabaseTasksMigrateTest < ActiveRecord::TestCase
+ def setup
+ ActiveRecord::Tasks::DatabaseTasks.migrations_paths = 'custom/path'
+ end
+
+ def teardown
+ ActiveRecord::Tasks::DatabaseTasks.migrations_paths = nil
+ end
+
def test_migrate_receives_correct_env_vars
verbose, version = ENV['VERBOSE'], ENV['VERSION']
- ActiveRecord::Tasks::DatabaseTasks.migrations_paths = 'custom/path'
ENV['VERBOSE'] = 'false'
ENV['VERSION'] = '4'
ActiveRecord::Migrator.expects(:migrate).with('custom/path', 4)
ActiveRecord::Tasks::DatabaseTasks.migrate
ensure
- ActiveRecord::Tasks::DatabaseTasks.migrations_paths = nil
ENV['VERBOSE'], ENV['VERSION'] = verbose, version
end
+
+ def test_migrate_clears_schema_cache_afterward
+ ActiveRecord::Base.expects(:clear_cache!)
+ ActiveRecord::Tasks::DatabaseTasks.migrate
+ end
end
class DatabaseTasksPurgeTest < ActiveRecord::TestCase
diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md
index b020f3bd41..b9dcbe53c1 100644
--- a/activesupport/CHANGELOG.md
+++ b/activesupport/CHANGELOG.md
@@ -25,7 +25,7 @@
*Tara Scherner de la Fuente*
-* Make `benchmark('something', silence: true)` actually work
+* Make `benchmark('something', silence: true)` actually work.
*DHH*
diff --git a/guides/source/active_record_validations.md b/guides/source/active_record_validations.md
index 10bd201145..bcfdb935b2 100644
--- a/guides/source/active_record_validations.md
+++ b/guides/source/active_record_validations.md
@@ -830,6 +830,25 @@ class Person < ApplicationRecord
end
```
+You can also use `on:` to define custom context.
+Custom contexts need to be triggered explicitly
+by passing name of the context to `valid?`, `invalid?` or `save`.
+
+```ruby
+class Person < ApplicationRecord
+ validates :email, uniqueness: true, on: :account_setup
+ validates :age, numericality: true, on: :account_setup
+end
+
+person = Person.new
+```
+
+`person.valid?(:account_setup)` executes both the validations
+without saving the model. And `person.save(context: :account_setup)`
+validates `person` in `account_setup` context before saving.
+On explicit triggers, model is validated by
+validations of only that context and validations without context.
+
Strict Validations
------------------