aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/lib')
-rw-r--r--activerecord/lib/active_record/attribute.rb8
-rw-r--r--activerecord/lib/active_record/attribute_methods/before_type_cast.rb5
-rw-r--r--activerecord/lib/active_record/attribute_methods/dirty.rb2
-rw-r--r--activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb33
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb3
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb8
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/quoting.rb3
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb2
-rw-r--r--activerecord/lib/active_record/locking/optimistic.rb8
-rw-r--r--activerecord/lib/active_record/persistence.rb12
-rw-r--r--activerecord/lib/active_record/secure_token.rb2
-rw-r--r--activerecord/lib/active_record/type/integer.rb8
-rw-r--r--activerecord/lib/active_record/type/time.rb13
-rw-r--r--activerecord/lib/active_record/type/time_value.rb4
-rw-r--r--activerecord/lib/active_record/type/value.rb3
15 files changed, 83 insertions, 31 deletions
diff --git a/activerecord/lib/active_record/attribute.rb b/activerecord/lib/active_record/attribute.rb
index 88536eaac0..51e4fae62e 100644
--- a/activerecord/lib/active_record/attribute.rb
+++ b/activerecord/lib/active_record/attribute.rb
@@ -74,6 +74,10 @@ module ActiveRecord
true
end
+ def came_from_user?
+ false
+ end
+
def ==(other)
self.class == other.class &&
name == other.name &&
@@ -99,6 +103,10 @@ module ActiveRecord
def type_cast(value)
type.type_cast_from_user(value)
end
+
+ def came_from_user?
+ true
+ end
end
class WithCastValue < Attribute # :nodoc:
diff --git a/activerecord/lib/active_record/attribute_methods/before_type_cast.rb b/activerecord/lib/active_record/attribute_methods/before_type_cast.rb
index fd61febd57..56c1898551 100644
--- a/activerecord/lib/active_record/attribute_methods/before_type_cast.rb
+++ b/activerecord/lib/active_record/attribute_methods/before_type_cast.rb
@@ -28,6 +28,7 @@ module ActiveRecord
included do
attribute_method_suffix "_before_type_cast"
+ attribute_method_suffix "_came_from_user?"
end
# Returns the value of the attribute identified by +attr_name+ before
@@ -66,6 +67,10 @@ module ActiveRecord
def attribute_before_type_cast(attribute_name)
read_attribute_before_type_cast(attribute_name)
end
+
+ def attribute_came_from_user?(attribute_name)
+ @attributes[attribute_name].came_from_user?
+ end
end
end
end
diff --git a/activerecord/lib/active_record/attribute_methods/dirty.rb b/activerecord/lib/active_record/attribute_methods/dirty.rb
index ce7f575150..bce9c5e1e3 100644
--- a/activerecord/lib/active_record/attribute_methods/dirty.rb
+++ b/activerecord/lib/active_record/attribute_methods/dirty.rb
@@ -108,7 +108,7 @@ module ActiveRecord
end
def save_changed_attribute(attr, old_value)
- if attribute_changed?(attr)
+ if attribute_changed_by_setter?(attr)
clear_attribute_changes(attr) unless _field_changed?(attr, old_value)
else
set_attribute_was(attr, old_value) if _field_changed?(attr, old_value)
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 777f7ab4d7..98671178cb 100644
--- a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb
+++ b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb
@@ -13,7 +13,7 @@ module ActiveRecord
value.map { |v| type_cast_from_user(v) }
elsif value.respond_to?(:in_time_zone)
begin
- value.in_time_zone || super
+ user_input_in_time_zone(value) || super
rescue ArgumentError
nil
end
@@ -39,6 +39,9 @@ module ActiveRecord
class_attribute :skip_time_zone_conversion_for_attributes, instance_writer: false
self.skip_time_zone_conversion_for_attributes = []
+
+ class_attribute :time_zone_aware_types, instance_writer: false
+ self.time_zone_aware_types = [:datetime, :not_explicitly_configured]
end
module ClassMethods
@@ -59,9 +62,31 @@ module ActiveRecord
end
def create_time_zone_conversion_attribute?(name, cast_type)
- time_zone_aware_attributes &&
- !self.skip_time_zone_conversion_for_attributes.include?(name.to_sym) &&
- (:datetime == cast_type.type)
+ enabled_for_column = time_zone_aware_attributes &&
+ !self.skip_time_zone_conversion_for_attributes.include?(name.to_sym)
+ result = enabled_for_column &&
+ time_zone_aware_types.include?(cast_type.type)
+
+ if enabled_for_column &&
+ !result &&
+ cast_type.type == :time &&
+ time_zone_aware_types.include?(:not_explicitly_configured)
+ ActiveSupport::Deprecation.warn(<<-MESSAGE)
+ Time columns will become time zone aware in Rails 5.1. This
+ still cause `String`s to be parsed as if they were in `Time.zone`,
+ and `Time`s to be converted to `Time.zone`.
+
+ To keep the old behavior, you must add the following to your initializer:
+
+ config.active_record.time_zone_aware_types = [:datetime]
+
+ To silence this deprecation warning, add the following:
+
+ config.active_record.time_zone_aware_types << :time
+ MESSAGE
+ end
+
+ result
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
index 6b5081b7a9..d99dc9a5db 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
@@ -454,7 +454,8 @@ module ActiveRecord
end
c
rescue
- disconnect!
+ remove c
+ c.disconnect!
raise
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
index 6e631ed9f7..787d07c4c2 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
@@ -289,7 +289,13 @@ module ActiveRecord
[columns[name], value]
end
key_list = fixture.keys.map { |name| quote_column_name(name) }
- value_list = prepare_binds_for_database(binds).map { |_, value| quote(value) }
+ value_list = prepare_binds_for_database(binds).map do |_, value|
+ begin
+ quote(value)
+ rescue TypeError
+ quote(YAML.dump(value))
+ end
+ end
execute "INSERT INTO #{quote_table_name(table_name)} (#{key_list.join(', ')}) VALUES (#{value_list.join(', ')})", 'Fixture Insert'
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
index 7c1a779577..c18caa2a2f 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
@@ -125,8 +125,7 @@ module ActiveRecord
when Date, Time then "'#{quoted_date(value)}'"
when Symbol then "'#{quote_string(value.to_s)}'"
when Class then "'#{value}'"
- else
- "'#{quote_string(YAML.dump(value))}'"
+ else raise TypeError, "can't quote #{value.class.name}"
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb
index c203e6c604..e45a2f59d9 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb
@@ -18,7 +18,7 @@ module ActiveRecord
end
attr_reader :subtype, :delimiter
- delegate :type, to: :subtype
+ delegate :type, :user_input_in_time_zone, to: :subtype
def initialize(subtype, delimiter = ',')
@subtype = subtype
diff --git a/activerecord/lib/active_record/locking/optimistic.rb b/activerecord/lib/active_record/locking/optimistic.rb
index aeb1a4ddc6..6f2b65c137 100644
--- a/activerecord/lib/active_record/locking/optimistic.rb
+++ b/activerecord/lib/active_record/locking/optimistic.rb
@@ -125,12 +125,8 @@ module ActiveRecord
relation = super
if locking_enabled?
- column_name = self.class.locking_column
- column = self.class.columns_hash[column_name]
- substitute = self.class.connection.substitute_at(column)
-
- relation = relation.where(self.class.arel_table[column_name].eq(substitute))
- relation.bind_values << [column, self[column_name].to_i]
+ locking_column = self.class.locking_column
+ relation = relation.where(locking_column => _read_attribute(locking_column))
end
relation
diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb
index cf6673db2e..714d36e7c0 100644
--- a/activerecord/lib/active_record/persistence.rb
+++ b/activerecord/lib/active_record/persistence.rb
@@ -246,7 +246,7 @@ module ActiveRecord
name = name.to_s
verify_readonly_attribute(name)
send("#{name}=", value)
- save(validate: false)
+ save(validate: false) if changed?
end
# Updates the attributes of the model from the passed-in hash and saves the
@@ -495,15 +495,7 @@ module ActiveRecord
end
def relation_for_destroy
- pk = self.class.primary_key
- column = self.class.columns_hash[pk]
- substitute = self.class.connection.substitute_at(column)
-
- relation = self.class.unscoped.where(
- self.class.arel_table[pk].eq(substitute))
-
- relation.bind_values = [[column, id]]
- relation
+ self.class.unscoped.where(self.class.primary_key => id)
end
def create_or_update(*args)
diff --git a/activerecord/lib/active_record/secure_token.rb b/activerecord/lib/active_record/secure_token.rb
index be3c3bc847..07031b6371 100644
--- a/activerecord/lib/active_record/secure_token.rb
+++ b/activerecord/lib/active_record/secure_token.rb
@@ -5,7 +5,7 @@ module ActiveRecord
module ClassMethods
# Example using has_secure_token
#
- # # Schema: User(toke:string, auth_token:string)
+ # # Schema: User(token:string, auth_token:string)
# class User < ActiveRecord::Base
# has_secure_token
# has_secure_token :auth_token
diff --git a/activerecord/lib/active_record/type/integer.rb b/activerecord/lib/active_record/type/integer.rb
index fc260a081a..394fe008f9 100644
--- a/activerecord/lib/active_record/type/integer.rb
+++ b/activerecord/lib/active_record/type/integer.rb
@@ -3,6 +3,10 @@ module ActiveRecord
class Integer < Value # :nodoc:
include Numeric
+ # Column storage size in bytes.
+ # 4 bytes means a MySQL int or Postgres integer as opposed to smallint etc.
+ DEFAULT_LIMIT = 4
+
def initialize(*)
super
@range = min_value...max_value
@@ -38,12 +42,12 @@ module ActiveRecord
def ensure_in_range(value)
unless range.cover?(value)
- raise RangeError, "#{value} is out of range for #{self.class} with limit #{limit || 4}"
+ raise RangeError, "#{value} is out of range for #{self.class} with limit #{limit || DEFAULT_LIMIT}"
end
end
def max_value
- limit = self.limit || 4
+ limit = self.limit || DEFAULT_LIMIT
1 << (limit * 8 - 1) # 8 bits per byte with one bit for sign
end
diff --git a/activerecord/lib/active_record/type/time.rb b/activerecord/lib/active_record/type/time.rb
index 41f7d97f0c..cab1c7bf1e 100644
--- a/activerecord/lib/active_record/type/time.rb
+++ b/activerecord/lib/active_record/type/time.rb
@@ -7,6 +7,19 @@ module ActiveRecord
:time
end
+ def user_input_in_time_zone(value)
+ return unless value.present?
+
+ case value
+ when ::String
+ value = "2000-01-01 #{value}"
+ when ::Time
+ value = value.change(year: 2000, day: 1, month: 1)
+ end
+
+ super(value)
+ end
+
private
def cast_value(value)
diff --git a/activerecord/lib/active_record/type/time_value.rb b/activerecord/lib/active_record/type/time_value.rb
index d611d72dd4..8d9ac25643 100644
--- a/activerecord/lib/active_record/type/time_value.rb
+++ b/activerecord/lib/active_record/type/time_value.rb
@@ -9,6 +9,10 @@ module ActiveRecord
"'#{value.to_s(:db)}'"
end
+ def user_input_in_time_zone(value)
+ value.in_time_zone
+ end
+
private
def new_time(year, mon, mday, hour, min, sec, microsec, offset = nil)
diff --git a/activerecord/lib/active_record/type/value.rb b/activerecord/lib/active_record/type/value.rb
index 60ae47db3d..859b51ca90 100644
--- a/activerecord/lib/active_record/type/value.rb
+++ b/activerecord/lib/active_record/type/value.rb
@@ -3,8 +3,7 @@ module ActiveRecord
class Value # :nodoc:
attr_reader :precision, :scale, :limit
- # Valid options are +precision+, +scale+, and +limit+. They are only
- # used when dumping schema.
+ # Valid options are +precision+, +scale+, and +limit+.
def initialize(options = {})
options.assert_valid_keys(:precision, :scale, :limit)
@precision = options[:precision]