[DRE-commits] [SCM] ruby-activerecord-3.2.git branch, master, updated. debian/3.2.6-5-27-g2ee0c93
Ondřej Surý
ondrej at sury.org
Wed May 29 09:06:41 UTC 2013
The following commit has been merged in the master branch:
commit e9977191854161ae1a523f2d190fdb2a8446f250
Author: Ondřej Surý <ondrej at sury.org>
Date: Tue Mar 19 10:09:54 2013 +0100
Imported Upstream version 3.2.13
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 93c5aba..ec017f8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,289 @@
-## Rails 3.2.12 (unreleased) ##
+## Rails 3.2.13 (Feb 17, 2013) ##
+
+* Reverted 921a296a3390192a71abeec6d9a035cc6d1865c8, 'Quote numeric values
+ compared to string columns.' This caused several regressions.
+
+ *Steve Klabnik*
+
+* Fix overriding of attributes by default_scope on `ActiveRecord::Base#dup`.
+
+ *Hiroshige UMINO*
+
+* Fix issue with overriding Active Record reader methods with a composed object
+ and using that attribute as the scope of a `uniqueness_of` validation.
+ Backport #7072.
+
+ *Peter Brown*
+
+* Sqlite now preserves custom primary keys when copying or altering tables.
+ Fixes #9367.
+ Backport #2312.
+
+ *Sean Scally + Yves Senn*
+
+* Preloading `has_many :through` associations with conditions won't
+ cache the `:through` association. This will prevent invalid
+ subsets to be cached.
+ Fixes #8423.
+ Backport #9252.
+
+ Example:
+
+ class User
+ has_many :posts
+ has_many :recent_comments, -> { where('created_at > ?', 1.week.ago) }, :through => :posts
+ end
+
+ a_user = User.includes(:recent_comments).first
+
+ # this is preloaded
+ a_user.recent_comments
+
+ # fetching the recent_comments through the posts association won't preload it.
+ a_user.posts
+
+ *Yves Senn*
+
+* Fix handling of dirty time zone aware attributes
+
+ 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
+
+ Backport of #9073
+ Fixes #8898
+
+ *Lilibeth De La Cruz*
+
+* Fix counter cache columns not updated when replacing `has_many :through`
+ associations.
+ Backport #8400.
+ Fix #7630.
+
+ *Matthew Robertson*
+
+* Don't update `column_defaults` when calling destructive methods on column with default value.
+ Backport c517602.
+ Fix #6115.
+
+ *Piotr Sarnacki + Aleksey Magusev + Alan Daud*
+
+* When `#count` is used in conjunction with `#uniq` we perform `count(:distinct => true)`.
+ Fix #6865.
+
+ Example:
+
+ relation.uniq.count # => SELECT COUNT(DISTINCT *)
+
+ *Yves Senn + Kaspar Schiess*
+
+* Fix `ActiveRecord::Relation#pluck` when columns or tables are reserved words.
+ Backport #7536.
+ Fix #8968.
+
+ *Ian Lesperance + Yves Senn + Kaspar Schiess*
+
+* Don't run explain on slow queries for database adapters that don't support it.
+ Backport #6197.
+
+ *Blake Smith*
+
+* Revert round usec when comparing timestamp attributes in the dirty tracking.
+ Fixes #8460.
+
+ *Andrew White*
+
+* Revert creation of through association models when using `collection=[]`
+ on a `has_many :through` association from an unsaved model.
+ Fix #7661, #8269.
+
+ *Ernie Miller*
+
+* Fix undefined method `to_i` when calling `new` on a scope that uses an
+ Array; Fix FloatDomainError when setting integer column to NaN.
+ Fixes #8718, #8734, #8757.
+
+ *Jason Stirk + Tristan Harward*
+
+* Serialized attributes can be serialized in integer columns.
+ Fix #8575.
+
+ *Rafael Mendonça França*
+
+* Keep index names when using `alter_table` with sqlite3.
+ Fix #3489.
+ Backport #8522.
+
+ *Yves Senn*
+
+* Recognize migrations placed in directories containing numbers and 'rb'.
+ Fix #8492.
+ Backport of #8500.
+
+ *Yves Senn*
+
+* Add `ActiveRecord::Base.cache_timestamp_format` class attribute to control
+ the format of the timestamp value in the cache key.
+ This allows users to improve the precision of the cache key.
+ Fixes #8195.
+
+ *Rafael Mendonça França*
+
+* Add `:nsec` date format. This can be used to improve the precision of cache key.
+ Please note that this format only works with Ruby 1.9, Ruby 1.8 will ignore it completely.
+
+ *Jamie Gaskins*
+
+* Unscope `update_column(s)` query to ignore default scope.
+
+ 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
+
+ Backport of #8436 fix.
+
+ *Carlos Antonio da Silva*
+
+* Fix performance problem with primary_key method in PostgreSQL adapter when having many schemas.
+ Uses pg_constraint table instead of pg_depend table which has many records in general.
+ Fix #8414
+
+ *kennyj*
+
+* Do not instantiate intermediate Active Record objects when eager loading.
+ These records caused `after_find` to run more than expected.
+ Fix #3313
+ Backport of #8403
+
+ *Yves Senn*
+
+* Fix `pluck` to work with joins. Backport of #4942.
+
+ *Carlos Antonio da Silva*
+
+* Fix a problem with `translate_exception` method in a non English environment.
+ Backport of #6397.
+
+ *kennyj*
+
+* Fix dirty attribute checks for TimeZoneConversion with nil and blank
+ datetime attributes. Setting a nil datetime to a blank string should not
+ result in a change being flagged.
+ Fixes #8310.
+ Backport of #8311.
+
+ *Alisdair McDiarmid*
+
+* Prevent mass assignment to the type column of polymorphic associations when using `build`.
+ Fixes #8265.
+ Backport of #8291.
+
+ *Yves Senn*
+
+* When running migrations on Postgresql, the `:limit` option for `binary` and `text` columns is
+ silently dropped.
+ Previously, these migrations caused sql exceptions, because Postgresql doesn't support limits
+ on these types.
+
+ *Victor Costan*
+
+* Use `nil?` instead of `blank?` to check whether dynamic finder with a bang
+ should raise RecordNotFound.
+ Fixes #7238.
+
+ *Nikita Afanasenko*
+
+* Fix deleting from a HABTM join table upon destroying an object of a model
+ with optimistic locking enabled.
+ Fixes #5332.
+
+ *Nick Rogers*
+
+* Use query cache/uncache when using ENV["DATABASE_URL"].
+ Fixes #6951.
+ Backport of #8074.
+
+ *kennyj*
+
+* Do not create useless database transaction when building `has_one` association.
+
+ Example:
+
+ User.has_one :profile
+ User.new.build_profile
+
+ Backport of #8154.
+
+ *Bogdan Gusiev*
+
+* `AR::Base#attributes_before_type_cast` now returns unserialized values for serialized attributes.
+
+ *Nikita Afanasenko*
+
+* Fix issue that raises `NameError` when overriding the `accepts_nested_attributes` in child classes.
+
+ Before:
+
+ class Shared::Person < ActiveRecord::Base
+ has_one :address
+
+ accepts_nested_attributes :address, :reject_if => :all_blank
+ end
+
+ class Person < Shared::Person
+ accepts_nested_attributes :address
+ end
+
+ Person
+ #=> NameError: method `address_attributes=' not defined in Person
+
+ After:
+
+ Person
+ #=> Person(id: integer, ...)
+
+ Fixes #8131.
+
+ *Gabriel Sobrinho, Ricardo Henrique*
+
+
+## Rails 3.2.12 (Feb 11, 2013) ##
* Quote numeric values being compared to non-numeric columns. Otherwise,
in some database, the string column values will be coerced to a numeric
@@ -10,17 +295,24 @@
*Dylan Smith*
+
## Rails 3.2.11 (Jan 8, 2013) ##
* Fix querying with an empty hash *Damien Mathieu* [CVE-2013-0155]
-## Rails 3.2.10 ##
+
+## Rails 3.2.10 (Jan 2, 2013) ##
* CVE-2012-5664 options hashes should only be extracted if there are extra
parameters
+
## Rails 3.2.9 (Nov 12, 2012) ##
+* Fix `find_in_batches` crashing when IDs are strings and start option is not specified.
+
+ *Alexis Bernard*
+
* Fix issue with collection associations calling first(n)/last(n) and attempting
to set the inverse association when `:inverse_of` was used. Fixes #8087.
diff --git a/checksums.yaml.gz b/checksums.yaml.gz
index abc9b2c..b8116f7 100644
Binary files a/checksums.yaml.gz and b/checksums.yaml.gz differ
diff --git a/lib/active_record/associations/association.rb b/lib/active_record/associations/association.rb
index 59c1bad..ab0d888 100644
--- a/lib/active_record/associations/association.rb
+++ b/lib/active_record/associations/association.rb
@@ -231,7 +231,8 @@ module ActiveRecord
def build_record(attributes, options)
reflection.build_association(attributes, options) do |record|
- attributes = create_scope.except(*(record.changed - [reflection.foreign_key]))
+ skip_assign = [reflection.foreign_key, reflection.type].compact
+ attributes = create_scope.except(*(record.changed - skip_assign))
record.assign_attributes(attributes, :without_protection => true)
end
end
diff --git a/lib/active_record/associations/has_many_through_association.rb b/lib/active_record/associations/has_many_through_association.rb
index ce81333..2b9e7ea 100644
--- a/lib/active_record/associations/has_many_through_association.rb
+++ b/lib/active_record/associations/has_many_through_association.rb
@@ -38,20 +38,6 @@ module ActiveRecord
super
end
- def concat_records(records)
- ensure_not_nested
-
- records = super
-
- if owner.new_record? && records
- records.flatten.each do |record|
- build_through_record(record)
- end
- end
-
- records
- end
-
def insert_record(record, validate = true, raise = false)
ensure_not_nested
@@ -153,6 +139,11 @@ module ActiveRecord
delete_through_records(records)
+ if source_reflection.options[:counter_cache]
+ counter = source_reflection.counter_cache_column
+ klass.decrement_counter counter, records.map(&:id)
+ end
+
if through_reflection.macro == :has_many && update_through_counter?(method)
update_counter(-count, through_reflection)
end
diff --git a/lib/active_record/associations/has_one_association.rb b/lib/active_record/associations/has_one_association.rb
index 501ebe7..56f9013 100644
--- a/lib/active_record/associations/has_one_association.rb
+++ b/lib/active_record/associations/has_one_association.rb
@@ -11,7 +11,7 @@ module ActiveRecord
# If target and record are nil, or target is equal to record,
# we don't need to have transaction.
if (target || record) && target != record
- reflection.klass.transaction do
+ transaction_if(save) do
remove_target!(options[:dependent]) if target && !target.destroyed?
if record
@@ -70,6 +70,14 @@ module ActiveRecord
def nullify_owner_attributes(record)
record[reflection.foreign_key] = nil
end
+
+ def transaction_if(value)
+ if value
+ reflection.klass.transaction { yield }
+ else
+ yield
+ end
+ end
end
end
end
diff --git a/lib/active_record/associations/preloader/through_association.rb b/lib/active_record/associations/preloader/through_association.rb
index ad6374d..4cb7b56 100644
--- a/lib/active_record/associations/preloader/through_association.rb
+++ b/lib/active_record/associations/preloader/through_association.rb
@@ -37,7 +37,8 @@ module ActiveRecord
through_records = Array.wrap(owner.send(through_reflection.name))
# Dont cache the association - we would only be caching a subset
- if reflection.options[:source_type] && through_reflection.collection?
+ if (preload_options != through_options) ||
+ (reflection.options[:source_type] && through_reflection.collection?)
owner.association(through_reflection.name).reset
end
diff --git a/lib/active_record/attribute_methods/serialization.rb b/lib/active_record/attribute_methods/serialization.rb
index 00023b0..deb89f3 100644
--- a/lib/active_record/attribute_methods/serialization.rb
+++ b/lib/active_record/attribute_methods/serialization.rb
@@ -90,6 +90,14 @@ module ActiveRecord
end
end
+ def _field_changed?(attr, old, value)
+ if self.class.serialized_attributes.include?(attr)
+ old != value
+ else
+ super
+ end
+ end
+
def read_attribute_before_type_cast(attr_name)
if serialized_attributes.include?(attr_name)
super.unserialized_value
@@ -97,6 +105,16 @@ module ActiveRecord
super
end
end
+
+ def attributes_before_type_cast
+ super.dup.tap do |attributes|
+ self.class.serialized_attributes.each_key do |key|
+ if attributes.key?(key)
+ attributes[key] = attributes[key].unserialized_value
+ end
+ end
+ end
+ end
end
end
end
diff --git a/lib/active_record/attribute_methods/time_zone_conversion.rb b/lib/active_record/attribute_methods/time_zone_conversion.rb
index 4c3d5ee..6f3112e 100644
--- a/lib/active_record/attribute_methods/time_zone_conversion.rb
+++ b/lib/active_record/attribute_methods/time_zone_conversion.rb
@@ -37,18 +37,16 @@ module ActiveRecord
if create_time_zone_conversion_attribute?(attr_name, columns_hash[attr_name])
method_body, line = <<-EOV, __LINE__ + 1
def #{attr_name}=(original_time)
+ original_time = nil if original_time.blank?
time = original_time
unless time.acts_like?(:time)
time = time.is_a?(String) ? Time.zone.parse(time) : time.to_time rescue time
end
- zoned_time = time && time.in_time_zone rescue nil
- rounded_time = round_usec(zoned_time)
- rounded_value = round_usec(read_attribute("#{attr_name}"))
- if (rounded_value != rounded_time) || (!rounded_value && original_time)
- write_attribute("#{attr_name}", original_time)
- #{attr_name}_will_change!
- @attributes_cache["#{attr_name}"] = zoned_time
- end
+ time = time.in_time_zone rescue nil if time
+ previous_time = attribute_changed?("#{attr_name}") ? changed_attributes["#{attr_name}"] : read_attribute(:#{attr_name})
+ write_attribute(:#{attr_name}, original_time)
+ #{attr_name}_will_change! if previous_time != time
+ @attributes_cache["#{attr_name}"] = time
end
EOV
generated_attribute_methods.module_eval(method_body, __FILE__, line)
@@ -62,12 +60,6 @@ module ActiveRecord
time_zone_aware_attributes && !self.skip_time_zone_conversion_for_attributes.include?(name.to_sym) && column.type.in?([:datetime, :timestamp])
end
end
-
- private
- def round_usec(value)
- return unless value
- value.change(:usec => 0)
- end
end
end
end
diff --git a/lib/active_record/attribute_methods/write.rb b/lib/active_record/attribute_methods/write.rb
index 8c6fa90..16aed73 100644
--- a/lib/active_record/attribute_methods/write.rb
+++ b/lib/active_record/attribute_methods/write.rb
@@ -54,12 +54,13 @@ module ActiveRecord
end
def convert_number_column_value(value)
- if value == false
+ case value
+ when FalseClass
0
- elsif value == true
+ when TrueClass
1
- elsif value.is_a?(String) && value.blank?
- nil
+ when String
+ value.presence
else
value
end
diff --git a/lib/active_record/base.rb b/lib/active_record/base.rb
index 62c8110..5bd1721 100644
--- a/lib/active_record/base.rb
+++ b/lib/active_record/base.rb
@@ -479,7 +479,8 @@ module ActiveRecord #:nodoc:
# # Instantiates a single new object bypassing mass-assignment security
# User.new({ :first_name => 'Jamie', :is_admin => true }, :without_protection => true)
def initialize(attributes = nil, options = {})
- @attributes = self.class.initialize_attributes(self.class.column_defaults.dup)
+ defaults = Hash[self.class.column_defaults.map { |k, v| [k, v.duplicable? ? v.dup : v] }]
+ @attributes = self.class.initialize_attributes(defaults)
@association_cache = {}
@aggregation_cache = {}
@attributes_cache = {}
@@ -552,12 +553,11 @@ module ActiveRecord #:nodoc:
@new_record = true
ensure_proper_type
- populate_with_current_scope_attributes
super
end
# Backport dup from 1.9 so that initialize_dup() gets called
- unless Object.respond_to?(:initialize_dup)
+ unless Object.respond_to?(:initialize_dup, true)
def dup # :nodoc:
copy = super
copy.initialize_dup(self)
diff --git a/lib/active_record/connection_adapters/abstract/database_statements.rb b/lib/active_record/connection_adapters/abstract/database_statements.rb
index db99c3f..2703c2e 100644
--- a/lib/active_record/connection_adapters/abstract/database_statements.rb
+++ b/lib/active_record/connection_adapters/abstract/database_statements.rb
@@ -266,7 +266,7 @@ module ActiveRecord
# Inserts the given fixture into the table. Overridden in adapters that require
# something beyond a simple insert (eg. Oracle).
def insert_fixture(fixture, table_name)
- columns = Hash[columns(table_name).map { |c| [c.name, c] }]
+ columns = schema_cache.columns_hash(table_name)
key_list = []
value_list = fixture.map do |name, value|
diff --git a/lib/active_record/connection_adapters/abstract/quoting.rb b/lib/active_record/connection_adapters/abstract/quoting.rb
index fe0b195..f93c7cd 100644
--- a/lib/active_record/connection_adapters/abstract/quoting.rb
+++ b/lib/active_record/connection_adapters/abstract/quoting.rb
@@ -25,19 +25,13 @@ module ActiveRecord
when true, false
if column && column.type == :integer
value ? '1' : '0'
- elsif column && [:text, :string, :binary].include?(column.type)
- value ? "'1'" : "'0'"
else
value ? quoted_true : quoted_false
end
# BigDecimals need to be put in a non-normalized form and quoted.
when nil then "NULL"
- when Numeric, ActiveSupport::Duration
- value = BigDecimal === value ? value.to_s('F') : value.to_s
- if column && ![:integer, :float, :decimal].include?(column.type)
- value = "'#{value}'"
- end
- value
+ when BigDecimal then value.to_s('F')
+ when Numeric then value.to_s
when Date, Time then "'#{quoted_date(value)}'"
when Symbol then "'#{quote_string(value.to_s)}'"
else
diff --git a/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
index 61c5e80..abccc3a 100644
--- a/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
+++ b/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
@@ -199,6 +199,8 @@ module ActiveRecord
if value.kind_of?(String) && column && column.type == :binary && column.class.respond_to?(:string_to_binary)
s = column.class.string_to_binary(value).unpack("H*")[0]
"x'#{s}'"
+ elsif value.kind_of?(BigDecimal)
+ value.to_s("F")
else
super
end
diff --git a/lib/active_record/connection_adapters/column.rb b/lib/active_record/connection_adapters/column.rb
index e6269c7..e22d9f7 100644
--- a/lib/active_record/connection_adapters/column.rb
+++ b/lib/active_record/connection_adapters/column.rb
@@ -175,7 +175,7 @@ module ActiveRecord
when TrueClass, FalseClass
value ? 1 : 0
else
- value.to_i
+ value.to_i rescue nil
end
end
diff --git a/lib/active_record/connection_adapters/mysql_adapter.rb b/lib/active_record/connection_adapters/mysql_adapter.rb
index c132692..4850b68 100644
--- a/lib/active_record/connection_adapters/mysql_adapter.rb
+++ b/lib/active_record/connection_adapters/mysql_adapter.rb
@@ -2,7 +2,7 @@ require 'active_record/connection_adapters/abstract_mysql_adapter'
require 'active_record/connection_adapters/statement_pool'
require 'active_support/core_ext/hash/keys'
-gem 'mysql', '~> 2.8.1'
+gem 'mysql', '~> 2.8'
require 'mysql'
class Mysql
diff --git a/lib/active_record/connection_adapters/postgresql_adapter.rb b/lib/active_record/connection_adapters/postgresql_adapter.rb
index 80a0c6d..8806693 100644
--- a/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -315,8 +315,6 @@ module ActiveRecord
@visitor = BindSubstitution.new self
end
- connection_parameters.delete :prepared_statements
-
@connection_parameters, @config = connection_parameters, config
# @local_tz is initialized as nil to avoid warnings when connect tries to use it
@@ -988,12 +986,11 @@ module ActiveRecord
# Returns just a table's primary key
def primary_key(table)
row = exec_query(<<-end_sql, 'SCHEMA').rows.first
- SELECT DISTINCT(attr.attname)
+ SELECT attr.attname
FROM pg_attribute attr
- INNER JOIN pg_depend dep ON attr.attrelid = dep.refobjid AND attr.attnum = dep.refobjsubid
INNER JOIN pg_constraint cons ON attr.attrelid = cons.conrelid AND attr.attnum = cons.conkey[1]
WHERE cons.contype = 'p'
- AND dep.refobjid = '#{quote_table_name(table)}'::regclass
+ AND cons.conrelid = '#{quote_table_name(table)}'::regclass
end_sql
row && row.first
@@ -1078,6 +1075,13 @@ module ActiveRecord
when nil, 0..0x3fffffff; super(type)
else raise(ActiveRecordError, "No binary type has byte size #{limit}.")
end
+ when 'text'
+ # PostgreSQL doesn't support limits on text columns.
+ # The hard limit is 1Gb, according to section 8.3 in the manual.
+ case limit
+ when nil, 0..0x3fffffff; super(type)
+ else raise(ActiveRecordError, "The limit on text can be at most 1GB - 1byte.")
+ end
when 'integer'
return 'integer' unless limit
@@ -1135,11 +1139,15 @@ module ActiveRecord
@connection.server_version
end
+ # See http://www.postgresql.org/docs/9.1/static/errcodes-appendix.html
+ FOREIGN_KEY_VIOLATION = "23503"
+ UNIQUE_VIOLATION = "23505"
+
def translate_exception(exception, message)
- case exception.message
- when /duplicate key value violates unique constraint/
+ case exception.result.error_field(PGresult::PG_DIAG_SQLSTATE)
+ when UNIQUE_VIOLATION
RecordNotUnique.new(message, exception)
- when /violates foreign key constraint/
+ when FOREIGN_KEY_VIOLATION
InvalidForeignKey.new(message, exception)
else
super
diff --git a/lib/active_record/connection_adapters/schema_cache.rb b/lib/active_record/connection_adapters/schema_cache.rb
index 4e8932a..bc8d24a 100644
--- a/lib/active_record/connection_adapters/schema_cache.rb
+++ b/lib/active_record/connection_adapters/schema_cache.rb
@@ -1,7 +1,7 @@
module ActiveRecord
module ConnectionAdapters
class SchemaCache
- attr_reader :columns, :columns_hash, :primary_keys, :tables
+ attr_reader :primary_keys, :tables
attr_reader :connection
def initialize(conn)
@@ -30,6 +30,25 @@ module ActiveRecord
@tables[name] = connection.table_exists?(name)
end
+ # Get the columns for a table
+ def columns(table = nil)
+ if table
+ @columns[table]
+ else
+ @columns
+ end
+ end
+
+ # Get the columns for a table as a hash, key is the column name
+ # value is the column object.
+ def columns_hash(table = nil)
+ if table
+ @columns_hash[table]
+ else
+ @columns_hash
+ end
+ end
+
# Clears out internal caches
def clear!
@columns.clear
diff --git a/lib/active_record/connection_adapters/sqlite_adapter.rb b/lib/active_record/connection_adapters/sqlite_adapter.rb
index e80b465..455560a 100644
--- a/lib/active_record/connection_adapters/sqlite_adapter.rb
+++ b/lib/active_record/connection_adapters/sqlite_adapter.rb
@@ -490,7 +490,11 @@ module ActiveRecord
end
def copy_table(from, to, options = {}) #:nodoc:
- options = options.merge(:id => (!columns(from).detect{|c| c.name == 'id'}.nil? && 'id' == primary_key(from).to_s))
+ from_primary_key = primary_key(from)
+ options[:primary_key] = from_primary_key if from_primary_key != 'id'
+ unless options[:primary_key]
+ options[:id] = !columns(from).detect{|c| c.name == 'id'}.nil? && 'id' == from_primary_key
+ end
create_table(to, options) do |definition|
@definition = definition
columns(from).each do |column|
@@ -504,7 +508,7 @@ module ActiveRecord
:precision => column.precision, :scale => column.scale,
:null => column.null)
end
- @definition.primary_key(primary_key(from)) if primary_key(from)
+ @definition.primary_key(from_primary_key) if from_primary_key
yield @definition if block_given?
end
@@ -530,7 +534,7 @@ module ActiveRecord
unless columns.empty?
# index name can't be the same
- opts = { :name => name.gsub(/_(#{from})_/, "_#{to}_") }
+ opts = { :name => name.gsub(/(^|_)(#{from})_/, "\\1#{to}_") }
opts[:unique] = true if index.unique
add_index(to, columns, opts)
end
diff --git a/lib/active_record/explain.rb b/lib/active_record/explain.rb
index bdccf53..236834f 100644
--- a/lib/active_record/explain.rb
+++ b/lib/active_record/explain.rb
@@ -11,11 +11,12 @@ module ActiveRecord
end
end
- # If auto explain is enabled, this method triggers EXPLAIN logging for the
- # queries triggered by the block if it takes more than the threshold as a
- # whole. That is, the threshold is not checked against each individual
- # query, but against the duration of the entire block. This approach is
- # convenient for relations.
+ # If the database adapter supports explain and auto explain is enabled,
+ # this method triggers EXPLAIN logging for the queries triggered by the
+ # block if it takes more than the threshold as a whole. That is, the
+ # threshold is not checked against each individual query, but against the
+ # duration of the entire block. This approach is convenient for relations.
+
#
# The available_queries_for_explain thread variable collects the queries
# to be explained. If the value is nil, it means queries are not being
@@ -26,7 +27,7 @@ module ActiveRecord
threshold = auto_explain_threshold_in_seconds
current = Thread.current
- if threshold && current[:available_queries_for_explain].nil?
+ if connection.supports_explain? && threshold && current[:available_queries_for_explain].nil?
begin
queries = current[:available_queries_for_explain] = []
start = Time.now
diff --git a/lib/active_record/integration.rb b/lib/active_record/integration.rb
index 2c42f4c..f2ace18 100644
--- a/lib/active_record/integration.rb
+++ b/lib/active_record/integration.rb
@@ -1,5 +1,16 @@
module ActiveRecord
module Integration
+ extend ActiveSupport::Concern
+
+ included do
+ ##
+ # :singleton-method:
+ # Indicates the format used to generate the timestamp format in the cache key.
+ # This is +:number+, by default.
+ class_attribute :cache_timestamp_format, :instance_writer => false
+ self.cache_timestamp_format = :number
+ end
+
# Returns a String, which Action Pack uses for constructing an URL to this
# object. The default implementation returns this record's id as a String,
# or nil if this record's unsaved.
@@ -39,7 +50,7 @@ module ActiveRecord
when new_record?
"#{self.class.model_name.cache_key}/new"
when timestamp = self[:updated_at]
- timestamp = timestamp.utc.to_s(:number)
+ timestamp = timestamp.utc.to_s(cache_timestamp_format)
"#{self.class.model_name.cache_key}/#{id}-#{timestamp}"
else
"#{self.class.model_name.cache_key}/#{id}"
diff --git a/lib/active_record/locking/optimistic.rb b/lib/active_record/locking/optimistic.rb
index 7deac25..b288199 100644
--- a/lib/active_record/locking/optimistic.rb
+++ b/lib/active_record/locking/optimistic.rb
@@ -102,6 +102,8 @@ module ActiveRecord
def destroy #:nodoc:
return super unless locking_enabled?
+ destroy_associations
+
if persisted?
table = self.class.arel_table
lock_col = self.class.locking_column
diff --git a/lib/active_record/log_subscriber.rb b/lib/active_record/log_subscriber.rb
index a25f2c7..2b6488f 100644
--- a/lib/active_record/log_subscriber.rb
+++ b/lib/active_record/log_subscriber.rb
@@ -32,7 +32,11 @@ module ActiveRecord
unless (payload[:binds] || []).empty?
binds = " " + payload[:binds].map { |col,v|
- [col.name, v]
+ if col
+ [col.name, v]
+ else
+ [nil, v]
+ end
}.inspect
end
diff --git a/lib/active_record/migration.rb b/lib/active_record/migration.rb
index e668659..e8ec934 100644
--- a/lib/active_record/migration.rb
+++ b/lib/active_record/migration.rb
@@ -458,7 +458,7 @@ module ActiveRecord
say_with_time "#{method}(#{arg_list})" do
unless reverting?
unless arguments.empty? || method == :execute
- arguments[0] = Migrator.proper_table_name(arguments.first)
+ arguments[0] = Migrator.proper_table_name(arguments.first) unless method == :assume_migrated_upto_version
arguments[1] = Migrator.proper_table_name(arguments.second) if method == :rename_table
end
end
@@ -627,7 +627,7 @@ module ActiveRecord
seen = Hash.new false
migrations = files.map do |file|
- version, name, scope = file.scan(/([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?.rb/).first
+ version, name, scope = file.scan(/([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?\.rb\z/).first
raise IllegalMigrationNameError.new(file) unless version
version = version.to_i
diff --git a/lib/active_record/nested_attributes.rb b/lib/active_record/nested_attributes.rb
index d2065d7..0509165 100644
--- a/lib/active_record/nested_attributes.rb
+++ b/lib/active_record/nested_attributes.rb
@@ -277,13 +277,14 @@ module ActiveRecord
type = (reflection.collection? ? :collection : :one_to_one)
+ # remove_possible_method :pirate_attributes=
+ #
# def pirate_attributes=(attributes)
# assign_nested_attributes_for_one_to_one_association(:pirate, attributes, mass_assignment_options)
# end
class_eval <<-eoruby, __FILE__, __LINE__ + 1
- if method_defined?(:#{association_name}_attributes=)
- remove_method(:#{association_name}_attributes=)
- end
+ remove_possible_method(:#{association_name}_attributes=)
+
def #{association_name}_attributes=(attributes)
assign_nested_attributes_for_#{type}_association(:#{association_name}, attributes, mass_assignment_options)
end
diff --git a/lib/active_record/persistence.rb b/lib/active_record/persistence.rb
index fd3380a..36b6b5f 100644
--- a/lib/active_record/persistence.rb
+++ b/lib/active_record/persistence.rb
@@ -194,7 +194,7 @@ module ActiveRecord
raise ActiveRecordError, "#{name} is marked as readonly" if self.class.readonly_attributes.include?(name)
raise ActiveRecordError, "can not update on a new record object" unless persisted?
- updated_count = self.class.update_all({ name => value }, self.class.primary_key => id)
+ updated_count = self.class.unscoped.update_all({ name => value }, self.class.primary_key => id)
raw_write_attribute(name, value)
diff --git a/lib/active_record/query_cache.rb b/lib/active_record/query_cache.rb
index 466d148..2156889 100644
--- a/lib/active_record/query_cache.rb
+++ b/lib/active_record/query_cache.rb
@@ -6,19 +6,19 @@ module ActiveRecord
module ClassMethods
# Enable the query cache within the block if Active Record is configured.
def cache(&block)
- if ActiveRecord::Base.configurations.blank?
- yield
- else
+ if ActiveRecord::Base.connected?
connection.cache(&block)
+ else
+ yield
end
end
# Disable the query cache within the block if Active Record is configured.
def uncached(&block)
- if ActiveRecord::Base.configurations.blank?
- yield
- else
+ if ActiveRecord::Base.connected?
connection.uncached(&block)
+ else
+ yield
end
end
end
diff --git a/lib/active_record/railtie.rb b/lib/active_record/railtie.rb
index 13b7c6e..055d27d 100644
--- a/lib/active_record/railtie.rb
+++ b/lib/active_record/railtie.rb
@@ -83,6 +83,13 @@ module ActiveRecord
end
end
+ initializer "active_record.validate_explain_support" do |app|
+ if app.config.active_record[:auto_explain_threshold_in_seconds] &&
+ !ActiveRecord::Base.connection.supports_explain?
+ warn "auto_explain_threshold_in_seconds is set but will be ignored because your adapter does not support this feature. Please unset the configuration to avoid this warning."
+ end
+ end
+
# Expose database runtime to controller for logging.
initializer "active_record.log_runtime" do |app|
require "active_record/railties/controller_runtime"
diff --git a/lib/active_record/railties/databases.rake b/lib/active_record/railties/databases.rake
index ae6d9c8..8f7c7f6 100644
--- a/lib/active_record/railties/databases.rake
+++ b/lib/active_record/railties/databases.rake
@@ -64,10 +64,21 @@ db_namespace = namespace :db do
end
end
+ # If neither encoding nor collation is specified, use the utf-8 defaults.
def mysql_creation_options(config)
- @charset = ENV['CHARSET'] || 'utf8'
- @collation = ENV['COLLATION'] || 'utf8_unicode_ci'
- {:charset => (config['encoding'] || @charset), :collation => (config['collation'] || @collation)}
+ default_charset = ENV['CHARSET'] || 'utf8'
+ default_collation = ENV['COLLATION'] || 'utf8_unicode_ci'
+
+ Hash.new.tap do |options|
+ options[:charset] = config['encoding'] if config.include? 'encoding'
+ options[:collation] = config['collation'] if config.include? 'collation'
+
+ # Set default charset only when collation isn't set.
+ options[:charset] ||= default_charset unless options[:collation]
+
+ # Set default collation only when charset is also default.
+ options[:collation] ||= default_collation if options[:charset] == default_charset
+ end
end
def create_database(config)
@@ -101,9 +112,12 @@ db_namespace = namespace :db do
error_class = config['adapter'] =~ /mysql2/ ? Mysql2::Error : Mysql::Error
end
access_denied_error = 1045
+
+ create_options = mysql_creation_options(config)
+
begin
ActiveRecord::Base.establish_connection(config.merge('database' => nil))
- ActiveRecord::Base.connection.create_database(config['database'], mysql_creation_options(config))
+ ActiveRecord::Base.connection.create_database(config['database'], create_options)
ActiveRecord::Base.establish_connection(config)
rescue error_class => sqlerr
if sqlerr.errno == access_denied_error
@@ -119,7 +133,7 @@ db_namespace = namespace :db do
ActiveRecord::Base.establish_connection(config)
else
$stderr.puts sqlerr.error
- $stderr.puts "Couldn't create database for #{config.inspect}, charset: #{config['encoding'] || @charset}, collation: #{config['collation'] || @collation}"
+ $stderr.puts "Couldn't create database for #{config.inspect}, charset: #{create_options[:charset]}, collation: #{create_options[:collation]}"
$stderr.puts "(if you set the charset manually, make sure you have a matching collation)" if config['encoding']
end
end
@@ -419,11 +433,11 @@ db_namespace = namespace :db do
when 'sqlserver'
`smoscript -s #{config['host']} -d #{config['database']} -u #{config['username']} -p #{config['password']} -f #{filename} -A -U`
when "firebird"
- set_firebird_env(abcs[Rails.env])
- db_string = firebird_db_string(abcs[Rails.env])
+ set_firebird_env(config)
+ db_string = firebird_db_string(config)
sh "isql -a #{db_string} > #{filename}"
else
- raise "Task not supported by '#{abcs[Rails.env]["adapter"]}'"
+ raise "Task not supported by '#{config['adapter']}'"
end
if ActiveRecord::Base.connection.supports_migrations?
diff --git a/lib/active_record/relation.rb b/lib/active_record/relation.rb
index 4b3b30d..ae1a575 100644
--- a/lib/active_record/relation.rb
+++ b/lib/active_record/relation.rb
@@ -464,7 +464,7 @@ module ActiveRecord
node.left.relation.name == table_name
}
- Hash[equalities.map { |where| [where.left.name, where.right] }]
+ Hash[equalities.map { |where| [where.left.name, where.right] }].with_indifferent_access
end
def scope_for_create
diff --git a/lib/active_record/relation/batches.rb b/lib/active_record/relation/batches.rb
index 2fd8988..14701f6 100644
--- a/lib/active_record/relation/batches.rb
+++ b/lib/active_record/relation/batches.rb
@@ -59,11 +59,11 @@ module ActiveRecord
relation = apply_finder_options(finder_options)
end
- start = options.delete(:start).to_i
+ start = options.delete(:start)
batch_size = options.delete(:batch_size) || 1000
relation = relation.reorder(batch_order).limit(batch_size)
- records = relation.where(table[primary_key].gteq(start)).all
+ records = start ? relation.where(table[primary_key].gteq(start)).to_a : relation.to_a
while records.any?
records_size = records.size
diff --git a/lib/active_record/relation/calculations.rb b/lib/active_record/relation/calculations.rb
index 802059d..1f9dbdc 100644
--- a/lib/active_record/relation/calculations.rb
+++ b/lib/active_record/relation/calculations.rb
@@ -177,8 +177,15 @@ module ActiveRecord
# Person.where(:confirmed => true).limit(5).pluck(:id)
#
def pluck(column_name)
- column_name = column_name.to_s
- klass.connection.select_all(select(column_name).arel).map! do |attributes|
+ if column_name.is_a?(Symbol) && column_names.include?(column_name.to_s)
+ column_name = "#{connection.quote_table_name(table_name)}.#{connection.quote_column_name(column_name)}"
+ else
+ column_name = column_name.to_s
+ end
+
+ relation = clone
+ relation.select_values = [column_name]
+ klass.connection.select_all(relation.arel).map! do |attributes|
klass.type_cast_attribute(attributes.keys.first, klass.initialize_attributes(attributes))
end
end
@@ -188,7 +195,8 @@ module ActiveRecord
def perform_calculation(operation, column_name, options = {})
operation = operation.to_s.downcase
- distinct = options[:distinct]
+ # If #count is used in conjuction with #uniq it is considered distinct. (eg. relation.uniq.count)
+ distinct = options[:distinct] || self.uniq_value
if operation == "count"
column_name ||= (select_for_count || :all)
diff --git a/lib/active_record/relation/finder_methods.rb b/lib/active_record/relation/finder_methods.rb
index abc67d9..08cfe4f 100644
--- a/lib/active_record/relation/finder_methods.rb
+++ b/lib/active_record/relation/finder_methods.rb
@@ -253,9 +253,11 @@ module ActiveRecord
orders = relation.order_values.map { |val| val.presence }.compact
values = @klass.connection.distinct("#{@klass.connection.quote_table_name table_name}.#{primary_key}", orders)
- relation = relation.dup
+ relation = relation.dup.select(values)
+
+ id_rows = @klass.connection.select_all(relation.arel, 'SQL', relation.bind_values)
+ ids_array = id_rows.map {|row| row[primary_key]}
- ids_array = relation.select(values).collect {|row| row[primary_key]}
ids_array.empty? ? raise(ThrowResult) : table[primary_key].in(ids_array)
end
@@ -263,7 +265,7 @@ module ActiveRecord
conditions = Hash[attributes.map {|a| [a, args[attributes.index(a)]]}]
result = where(conditions).send(match.finder)
- if match.bang? && result.blank?
+ if match.bang? && result.nil?
raise RecordNotFound, "Couldn't find #{@klass.name} with #{conditions.to_a.collect {|p| p.join(' = ')}.join(', ')}"
else
yield(result) if block_given?
diff --git a/lib/active_record/relation/predicate_builder.rb b/lib/active_record/relation/predicate_builder.rb
index 236fd5c..413b81c 100644
--- a/lib/active_record/relation/predicate_builder.rb
+++ b/lib/active_record/relation/predicate_builder.rb
@@ -20,7 +20,7 @@ module ActiveRecord
table = Arel::Table.new(table_name, engine)
end
- attribute = table[column.to_sym]
+ attribute = table[column]
case value
when ActiveRecord::Relation
@@ -51,10 +51,6 @@ module ActiveRecord
when Class
# FIXME: I think we need to deprecate this behavior
attribute.eq(value.name)
- when Integer, ActiveSupport::Duration
- # Arel treats integers as literals, but they should be quoted when compared with strings
- column = engine.connection.schema_cache.columns_hash[table.name][attribute.name.to_s]
- attribute.eq(Arel::Nodes::SqlLiteral.new(engine.connection.quote(value, column)))
else
attribute.eq(value)
end
diff --git a/lib/active_record/result.rb b/lib/active_record/result.rb
index 9ceab2e..b8d2cd2 100644
--- a/lib/active_record/result.rb
+++ b/lib/active_record/result.rb
@@ -26,9 +26,15 @@ module ActiveRecord
private
def hash_rows
- @hash_rows ||= @rows.map { |row|
- Hash[@columns.zip(row)]
- }
+ @hash_rows ||=
+ begin
+ # We freeze the strings to prevent them getting duped when
+ # used as keys in ActiveRecord::Model's @attributes hash
+ columns = @columns.map { |c| c.dup.freeze }
+ @rows.map { |row|
+ Hash[columns.zip(row)]
+ }
+ end
end
end
end
diff --git a/lib/active_record/scoping/named.rb b/lib/active_record/scoping/named.rb
index d6b0265..767b30f 100644
--- a/lib/active_record/scoping/named.rb
+++ b/lib/active_record/scoping/named.rb
@@ -161,16 +161,14 @@ module ActiveRecord
# end
#
# def self.titles
- # map(&:title)
+ # pluck(:title)
# end
- #
# end
#
# We are able to call the methods like this:
#
# Article.published.featured.latest_article
# Article.featured.titles
-
def scope(name, scope_options = {})
name = name.to_sym
valid_scope_name?(name)
diff --git a/lib/active_record/validations/uniqueness.rb b/lib/active_record/validations/uniqueness.rb
index 154aace..7950885 100644
--- a/lib/active_record/validations/uniqueness.rb
+++ b/lib/active_record/validations/uniqueness.rb
@@ -26,7 +26,7 @@ module ActiveRecord
relation = relation.and(table[finder_class.primary_key.to_sym].not_eq(record.send(:id))) if record.persisted?
Array.wrap(options[:scope]).each do |scope_item|
- scope_value = record.send(scope_item)
+ scope_value = record.read_attribute(scope_item)
relation = relation.and(table[scope_item].eq(scope_value))
end
diff --git a/lib/active_record/version.rb b/lib/active_record/version.rb
index a340cfa..9069d99 100644
--- a/lib/active_record/version.rb
+++ b/lib/active_record/version.rb
@@ -2,7 +2,7 @@ module ActiveRecord
module VERSION #:nodoc:
MAJOR = 3
MINOR = 2
- TINY = 12
+ TINY = 13
PRE = nil
STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
diff --git a/metadata.yml b/metadata.yml
index 71e1f36..336bf0c 100644
--- a/metadata.yml
+++ b/metadata.yml
@@ -1,14 +1,14 @@
--- !ruby/object:Gem::Specification
name: activerecord
version: !ruby/object:Gem::Version
- version: 3.2.12
+ version: 3.2.13
platform: ruby
authors:
- David Heinemeier Hansson
autorequire:
bindir: bin
cert_chain: []
-date: 2013-02-11 00:00:00.000000000 Z
+date: 2013-03-18 00:00:00.000000000 Z
dependencies:
- !ruby/object:Gem::Dependency
name: activesupport
@@ -16,54 +16,54 @@ dependencies:
requirements:
- - '='
- !ruby/object:Gem::Version
- version: 3.2.12
+ version: 3.2.13
type: :runtime
prerelease: false
version_requirements: !ruby/object:Gem::Requirement
requirements:
- - '='
- !ruby/object:Gem::Version
- version: 3.2.12
+ version: 3.2.13
- !ruby/object:Gem::Dependency
name: activemodel
requirement: !ruby/object:Gem::Requirement
requirements:
- - '='
- !ruby/object:Gem::Version
- version: 3.2.12
+ version: 3.2.13
type: :runtime
prerelease: false
version_requirements: !ruby/object:Gem::Requirement
requirements:
- - '='
- !ruby/object:Gem::Version
- version: 3.2.12
+ version: 3.2.13
- !ruby/object:Gem::Dependency
name: arel
requirement: !ruby/object:Gem::Requirement
requirements:
- - - "~>"
+ - - ~>
- !ruby/object:Gem::Version
version: 3.0.2
type: :runtime
prerelease: false
version_requirements: !ruby/object:Gem::Requirement
requirements:
- - - "~>"
+ - - ~>
- !ruby/object:Gem::Version
version: 3.0.2
- !ruby/object:Gem::Dependency
name: tzinfo
requirement: !ruby/object:Gem::Requirement
requirements:
- - - "~>"
+ - - ~>
- !ruby/object:Gem::Version
version: 0.3.29
type: :runtime
prerelease: false
version_requirements: !ruby/object:Gem::Requirement
requirements:
- - - "~>"
+ - - ~>
- !ruby/object:Gem::Version
version: 0.3.29
description: Databases on Rails. Build a persistent domain model by mapping database
@@ -229,23 +229,23 @@ licenses: []
metadata: {}
post_install_message:
rdoc_options:
-- "--main"
+- --main
- README.rdoc
require_paths:
- lib
required_ruby_version: !ruby/object:Gem::Requirement
requirements:
- - - ">="
+ - - '>='
- !ruby/object:Gem::Version
version: 1.8.7
required_rubygems_version: !ruby/object:Gem::Requirement
requirements:
- - - ">="
+ - - '>='
- !ruby/object:Gem::Version
version: '0'
requirements: []
rubyforge_project:
-rubygems_version: 2.0.0.rc.2
+rubygems_version: 2.0.2
signing_key:
specification_version: 4
summary: Object-relational mapper framework (part of Rails).
--
ruby-activerecord-3.2.git
More information about the Pkg-ruby-extras-commits
mailing list