aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/lib')
-rw-r--r--activerecord/lib/active_record/associations/alias_tracker.rb36
-rw-r--r--activerecord/lib/active_record/associations/association.rb9
-rw-r--r--activerecord/lib/active_record/associations/collection_association.rb6
-rw-r--r--activerecord/lib/active_record/associations/collection_proxy.rb6
-rw-r--r--activerecord/lib/active_record/associations/has_one_association.rb2
-rw-r--r--activerecord/lib/active_record/associations/join_helper.rb3
-rw-r--r--activerecord/lib/active_record/associations/preloader/association.rb5
-rw-r--r--activerecord/lib/active_record/associations/singular_association.rb3
-rw-r--r--activerecord/lib/active_record/attribute_methods.rb2
-rw-r--r--activerecord/lib/active_record/attribute_methods/read.rb5
-rw-r--r--activerecord/lib/active_record/base.rb85
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb9
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb2
-rw-r--r--activerecord/lib/active_record/locking/optimistic.rb2
-rw-r--r--activerecord/lib/active_record/migration/command_recorder.rb2
-rw-r--r--activerecord/lib/active_record/named_scope.rb19
-rw-r--r--activerecord/lib/active_record/nested_attributes.rb8
-rw-r--r--activerecord/lib/active_record/persistence.rb4
-rw-r--r--activerecord/lib/active_record/railties/databases.rake13
-rw-r--r--activerecord/lib/active_record/reflection.rb46
-rw-r--r--activerecord/lib/active_record/relation.rb5
-rw-r--r--activerecord/lib/active_record/relation/calculations.rb16
-rw-r--r--activerecord/lib/active_record/relation/query_methods.rb4
-rw-r--r--activerecord/lib/active_record/relation/spawn_methods.rb2
-rw-r--r--activerecord/lib/active_record/version.rb4
25 files changed, 175 insertions, 123 deletions
diff --git a/activerecord/lib/active_record/associations/alias_tracker.rb b/activerecord/lib/active_record/associations/alias_tracker.rb
index bd98cf2f46..92ed844a2e 100644
--- a/activerecord/lib/active_record/associations/alias_tracker.rb
+++ b/activerecord/lib/active_record/associations/alias_tracker.rb
@@ -9,7 +9,7 @@ module ActiveRecord
# table_joins is an array of arel joins which might conflict with the aliases we assign here
def initialize(table_joins = [])
- @aliases = Hash.new
+ @aliases = Hash.new { |h,k| h[k] = initial_count_for(k) }
@table_joins = table_joins
end
@@ -26,8 +26,6 @@ module ActiveRecord
def aliased_name_for(table_name, aliased_name = nil)
aliased_name ||= table_name
- initialize_count_for(table_name) if aliases[table_name].nil?
-
if aliases[table_name].zero?
# If it's zero, we can have our table_name
aliases[table_name] = 1
@@ -36,8 +34,6 @@ module ActiveRecord
# Otherwise, we need to use an alias
aliased_name = connection.table_alias_for(aliased_name)
- initialize_count_for(aliased_name) if aliases[aliased_name].nil?
-
# Update the count
aliases[aliased_name] += 1
@@ -49,32 +45,24 @@ module ActiveRecord
end
end
- def pluralize(table_name, base)
- base.pluralize_table_names ? table_name.to_s.pluralize : table_name.to_s
- end
-
private
- def initialize_count_for(name)
- aliases[name] = 0
-
- unless Arel::Table === table_joins
- # quoted_name should be downcased as some database adapters (Oracle) return quoted name in uppercase
- quoted_name = connection.quote_table_name(name).downcase
+ def initial_count_for(name)
+ return 0 if Arel::Table === table_joins
- aliases[name] += table_joins.map { |join|
- # Table names + table aliases
- join.left.downcase.scan(
- /join(?:\s+\w+)?\s+(\S+\s+)?#{quoted_name}\son/
- ).size
- }.sum
- end
+ # quoted_name should be downcased as some database adapters (Oracle) return quoted name in uppercase
+ quoted_name = connection.quote_table_name(name).downcase
- aliases[name]
+ table_joins.map { |join|
+ # Table names + table aliases
+ join.left.downcase.scan(
+ /join(?:\s+\w+)?\s+(\S+\s+)?#{quoted_name}\son/
+ ).size
+ }.sum
end
def truncate(name)
- name[0..connection.table_alias_length-3]
+ name.slice(0, connection.table_alias_length - 2)
end
def connection
diff --git a/activerecord/lib/active_record/associations/association.rb b/activerecord/lib/active_record/associations/association.rb
index c3aee90124..daadc8aa81 100644
--- a/activerecord/lib/active_record/associations/association.rb
+++ b/activerecord/lib/active_record/associations/association.rb
@@ -224,6 +224,15 @@ module ActiveRecord
def association_class
@reflection.klass
end
+
+ def build_record(attributes, options)
+ reflection.build_association(attributes, options) do |record|
+ record.assign_attributes(
+ create_scope.except(*record.changed),
+ :without_protection => true
+ )
+ end
+ end
end
end
end
diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb
index 337a0d48f1..224e0095d9 100644
--- a/activerecord/lib/active_record/associations/collection_association.rb
+++ b/activerecord/lib/active_record/associations/collection_association.rb
@@ -423,12 +423,6 @@ module ActiveRecord
scoped.scope_for_create.stringify_keys
end
- def build_record(attributes, options)
- record = reflection.build_association(attributes, options)
- record.assign_attributes(create_scope.except(*record.changed), :without_protection => true)
- record
- end
-
def delete_or_destroy(records, method)
records = records.flatten
records.each { |record| raise_on_type_mismatch(record) }
diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb
index 5267116c42..7f7dec467a 100644
--- a/activerecord/lib/active_record/associations/collection_proxy.rb
+++ b/activerecord/lib/active_record/associations/collection_proxy.rb
@@ -58,10 +58,10 @@ module ActiveRecord
alias_method :new, :build
- def respond_to?(*args)
+ def respond_to?(name, include_private = false)
super ||
- (load_target && target.respond_to?(*args)) ||
- @association.klass.respond_to?(*args)
+ (load_target && target.respond_to?(name, include_private)) ||
+ @association.klass.respond_to?(name, include_private)
end
def method_missing(method, *args, &block)
diff --git a/activerecord/lib/active_record/associations/has_one_association.rb b/activerecord/lib/active_record/associations/has_one_association.rb
index 6b8201973a..2131edbc20 100644
--- a/activerecord/lib/active_record/associations/has_one_association.rb
+++ b/activerecord/lib/active_record/associations/has_one_association.rb
@@ -19,7 +19,7 @@ module ActiveRecord
if owner.persisted? && save && !record.save
nullify_owner_attributes(record)
- set_owner_attributes(target)
+ set_owner_attributes(target) if target
raise RecordNotSaved, "Failed to save the new associated #{reflection.name}."
end
end
diff --git a/activerecord/lib/active_record/associations/join_helper.rb b/activerecord/lib/active_record/associations/join_helper.rb
index 87e33891a5..f83138195c 100644
--- a/activerecord/lib/active_record/associations/join_helper.rb
+++ b/activerecord/lib/active_record/associations/join_helper.rb
@@ -32,8 +32,7 @@ module ActiveRecord
end
def table_alias_for(reflection, join = false)
- name = alias_tracker.pluralize(reflection.name, reflection.active_record)
- name << "_#{alias_suffix}"
+ name = "#{reflection.plural_name}_#{alias_suffix}"
name << "_join" if join
name
end
diff --git a/activerecord/lib/active_record/associations/preloader/association.rb b/activerecord/lib/active_record/associations/preloader/association.rb
index 7256dd5288..779f8164cc 100644
--- a/activerecord/lib/active_record/associations/preloader/association.rb
+++ b/activerecord/lib/active_record/associations/preloader/association.rb
@@ -68,7 +68,8 @@ module ActiveRecord
private
def associated_records_by_owner
- owner_keys = owners.map { |owner| owner[owner_key_name] }.compact.uniq
+ owners_map = owners_by_key
+ owner_keys = owners_map.keys.compact
if klass.nil? || owner_keys.empty?
records = []
@@ -84,7 +85,7 @@ module ActiveRecord
records.each do |record|
owner_key = record[association_key_name].to_s
- owners_by_key[owner_key].each do |owner|
+ owners_map[owner_key].each do |owner|
records_by_owner[owner] << record
end
end
diff --git a/activerecord/lib/active_record/associations/singular_association.rb b/activerecord/lib/active_record/associations/singular_association.rb
index ce1f2a5543..6b010064d5 100644
--- a/activerecord/lib/active_record/associations/singular_association.rb
+++ b/activerecord/lib/active_record/associations/singular_association.rb
@@ -26,8 +26,7 @@ module ActiveRecord
end
def build(attributes = {}, options = {})
- record = reflection.build_association(attributes, options)
- record.assign_attributes(create_scope.except(*record.changed), :without_protection => true)
+ record = build_record(attributes, options)
yield(record) if block_given?
set_new_record(record)
record
diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb
index 5833c65893..d0687ed0b6 100644
--- a/activerecord/lib/active_record/attribute_methods.rb
+++ b/activerecord/lib/active_record/attribute_methods.rb
@@ -61,7 +61,7 @@ module ActiveRecord
end
end
- def respond_to?(*args)
+ def respond_to?(name, include_private = false)
self.class.define_attribute_methods unless self.class.attribute_methods_generated?
super
end
diff --git a/activerecord/lib/active_record/attribute_methods/read.rb b/activerecord/lib/active_record/attribute_methods/read.rb
index 7d4182291a..9a50a20fbc 100644
--- a/activerecord/lib/active_record/attribute_methods/read.rb
+++ b/activerecord/lib/active_record/attribute_methods/read.rb
@@ -99,8 +99,9 @@ module ActiveRecord
# Returns the value of the attribute identified by <tt>attr_name</tt> after it has been typecast (for example,
# "2004-12-12" in a data column is cast to a date object, like Date.new(2004, 12, 12)).
def read_attribute(attr_name)
- if respond_to? "_#{attr_name}"
- send "_#{attr_name}" if @attributes.has_key?(attr_name.to_s)
+ method = "_#{attr_name}"
+ if respond_to? method
+ send method if @attributes.has_key?(attr_name.to_s)
else
_read_attribute attr_name
end
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index 6a5d282973..3b8df4f2f1 100644
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -709,6 +709,12 @@ module ActiveRecord #:nodoc:
connection_pool.columns_hash[table_name]
end
+ # Returns a hash where the keys are column names and the values are
+ # default values when instantiating the AR object for this table.
+ def column_defaults
+ connection_pool.column_defaults[table_name]
+ end
+
# Returns an array of column names as strings.
def column_names
@column_names ||= columns.map { |column| column.name }
@@ -1204,11 +1210,11 @@ MSG
end
def current_scope #:nodoc:
- Thread.current[:"#{self}_current_scope"]
+ Thread.current["#{self}_current_scope"]
end
def current_scope=(scope) #:nodoc:
- Thread.current[:"#{self}_current_scope"] = scope
+ Thread.current["#{self}_current_scope"] = scope
end
# Use this macro in your model to set a default scope for all operations on
@@ -1527,6 +1533,7 @@ MSG
@marked_for_destruction = false
@previously_changed = {}
@changed_attributes = {}
+ @relation = nil
ensure_proper_type
set_serialized_attributes
@@ -1535,9 +1542,8 @@ MSG
assign_attributes(attributes, options) if attributes
- result = yield self if block_given?
+ yield self if block_given?
run_callbacks :initialize
- result
end
# Populate +coder+ with attributes about this record that should be
@@ -1568,6 +1574,7 @@ MSG
# post.title # => 'hello world'
def init_with(coder)
@attributes = coder['attributes']
+ @relation = nil
set_serialized_attributes
@@ -1702,27 +1709,24 @@ MSG
return unless new_attributes
attributes = new_attributes.stringify_keys
- role = options[:as] || :default
-
multi_parameter_attributes = []
+ @mass_assignment_options = options
unless options[:without_protection]
- attributes = sanitize_for_mass_assignment(attributes, role)
+ attributes = sanitize_for_mass_assignment(attributes, mass_assignment_role)
end
attributes.each do |k, v|
if k.include?("(")
multi_parameter_attributes << [ k, v ]
+ elsif respond_to?("#{k}=")
+ send("#{k}=", v)
else
- method_name = "#{k}="
- if respond_to?(method_name)
- method(method_name).arity == -2 ? send(method_name, v, options) : send(method_name, v)
- else
- raise(UnknownAttributeError, "unknown attribute: #{k}")
- end
+ raise(UnknownAttributeError, "unknown attribute: #{k}")
end
end
+ @mass_assignment_options = nil
assign_multiparameter_attributes(multi_parameter_attributes)
end
@@ -1777,16 +1781,12 @@ MSG
# Note also that destroying a record preserves its ID in the model instance, so deleted
# models are still comparable.
def ==(comparison_object)
- comparison_object.equal?(self) ||
+ super ||
comparison_object.instance_of?(self.class) &&
id.present? &&
comparison_object.id == id
end
-
- # Delegates to ==
- def eql?(comparison_object)
- self == comparison_object
- end
+ alias :eql? :==
# Delegates to id in order to allow two records of the same type and id to work with something like:
# [ Person.find(1), Person.find(2), Person.find(3) ] & [ Person.find(1), Person.find(4) ] # => [ Person.find(1) ]
@@ -1804,6 +1804,15 @@ MSG
@attributes.frozen?
end
+ # Allows sort on objects
+ def <=>(other_object)
+ if other_object.is_a?(self.class)
+ self.to_key <=> other_object.to_key
+ else
+ nil
+ end
+ end
+
# Backport dup from 1.9 so that initialize_dup() gets called
unless Object.respond_to?(:initialize_dup)
def dup # :nodoc:
@@ -1882,12 +1891,33 @@ MSG
value
end
+ def mass_assignment_options
+ @mass_assignment_options ||= {}
+ end
+
+ def mass_assignment_role
+ mass_assignment_options[:as] || :default
+ end
+
private
+ # Under Ruby 1.9, Array#flatten will call #to_ary (recursively) on each of the elements
+ # of the array, and then rescues from the possible NoMethodError. If those elements are
+ # ActiveRecord::Base's, then this triggers the various method_missing's that we have,
+ # which significantly impacts upon performance.
+ #
+ # So we can avoid the method_missing hit by explicitly defining #to_ary as nil here.
+ #
+ # See also http://tenderlovemaking.com/2011/06/28/til-its-ok-to-return-nil-from-to_ary/
+ def to_ary # :nodoc:
+ nil
+ end
+
def set_serialized_attributes
- (@attributes.keys & self.class.serialized_attributes.keys).each do |key|
- coder = self.class.serialized_attributes[key]
- @attributes[key] = coder.load @attributes[key]
+ sattrs = self.class.serialized_attributes
+
+ sattrs.each do |key, coder|
+ @attributes[key] = coder.load @attributes[key] if @attributes.key?(key)
end
end
@@ -1897,8 +1927,9 @@ MSG
# do Reply.new without having to set <tt>Reply[Reply.inheritance_column] = "Reply"</tt> yourself.
# No such attribute would be set for objects of the Message class in that example.
def ensure_proper_type
- unless self.class.descends_from_active_record?
- write_attribute(self.class.inheritance_column, self.class.sti_name)
+ klass = self.class
+ if klass.finder_needs_type_condition?
+ write_attribute(klass.inheritance_column, klass.sti_name)
end
end
@@ -2072,8 +2103,10 @@ MSG
end
def populate_with_current_scope_attributes
- self.class.scoped.scope_for_create.each do |att,value|
- respond_to?("#{att}=") && send("#{att}=", value)
+ return unless self.class.scope_attributes?
+
+ self.class.scope_attributes.each do |att,value|
+ send("#{att}=", value) if respond_to?("#{att}=")
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 090f6bc6fe..ddfdb05297 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
@@ -60,6 +60,7 @@ module ActiveRecord
attr_accessor :automatic_reconnect
attr_reader :spec, :connections
attr_reader :columns, :columns_hash, :primary_keys, :tables
+ attr_reader :column_defaults
# Creates a new ConnectionPool object. +spec+ is a ConnectionSpecification
# object which describes database connection information (e.g. adapter,
@@ -106,6 +107,12 @@ module ActiveRecord
}]
end
+ @column_defaults = Hash.new do |h, table_name|
+ h[table_name] = Hash[columns[table_name].map { |col|
+ [col.name, col.default]
+ }]
+ end
+
@primary_keys = Hash.new do |h, table_name|
h[table_name] = with_connection do |conn|
table_exists?(table_name) ? conn.primary_key(table_name) : 'id'
@@ -133,6 +140,7 @@ module ActiveRecord
def clear_cache!
@columns.clear
@columns_hash.clear
+ @column_defaults.clear
@tables.clear
end
@@ -140,6 +148,7 @@ module ActiveRecord
def clear_table_cache!(table_name)
@columns.delete table_name
@columns_hash.delete table_name
+ @column_defaults.delete table_name
@primary_keys.delete table_name
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index 6d638628df..29dd0a9ea3 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -940,7 +940,7 @@ module ActiveRecord
# Construct a clean list of column names from the ORDER BY clause, removing
# any ASC/DESC modifiers
- order_columns = orders.collect { |s| s =~ /^(.+)\s+(ASC|DESC)\s*$/i ? $1 : s }
+ order_columns = orders.collect { |s| s.gsub(/\s+(ASC|DESC)\s*/i, '') }
order_columns.delete_if { |c| c.blank? }
order_columns = order_columns.zip((0...order_columns.size).to_a).map { |s,i| "#{s} AS alias_#{i}" }
diff --git a/activerecord/lib/active_record/locking/optimistic.rb b/activerecord/lib/active_record/locking/optimistic.rb
index 3afa257a76..6cfce6e573 100644
--- a/activerecord/lib/active_record/locking/optimistic.rb
+++ b/activerecord/lib/active_record/locking/optimistic.rb
@@ -73,7 +73,7 @@ module ActiveRecord
# <tt>locking_enabled?</tt> at this point as
# <tt>@attributes</tt> may not have been initialized yet.
- if lock_optimistically && result.include?(self.class.locking_column)
+ if result.key?(self.class.locking_column) && lock_optimistically
result[self.class.locking_column] ||= 0
end
diff --git a/activerecord/lib/active_record/migration/command_recorder.rb b/activerecord/lib/active_record/migration/command_recorder.rb
index c98abab091..2eeff7e36f 100644
--- a/activerecord/lib/active_record/migration/command_recorder.rb
+++ b/activerecord/lib/active_record/migration/command_recorder.rb
@@ -48,7 +48,7 @@ module ActiveRecord
super || delegate.respond_to?(*args)
end
- [:create_table, :rename_table, :add_column, :remove_column, :rename_index, :rename_column, :add_index, :remove_index, :add_timestamps, :remove_timestamps, :change_column, :change_column_default].each do |method|
+ [:create_table, :change_table, :rename_table, :add_column, :remove_column, :rename_index, :rename_column, :add_index, :remove_index, :add_timestamps, :remove_timestamps, :change_column, :change_column_default].each do |method|
class_eval <<-EOV, __FILE__, __LINE__ + 1
def #{method}(*args) # def create_table(*args)
record(:"#{method}", args) # record(:create_table, args)
diff --git a/activerecord/lib/active_record/named_scope.rb b/activerecord/lib/active_record/named_scope.rb
index 14db7a6cd6..0313abe456 100644
--- a/activerecord/lib/active_record/named_scope.rb
+++ b/activerecord/lib/active_record/named_scope.rb
@@ -40,6 +40,25 @@ module ActiveRecord
end
end
+ ##
+ # Collects attributes from scopes that should be applied when creating
+ # an AR instance for the particular class this is called on.
+ def scope_attributes # :nodoc:
+ if current_scope
+ current_scope.scope_for_create
+ else
+ scope = relation.clone
+ scope.default_scoped = true
+ scope.scope_for_create
+ end
+ end
+
+ ##
+ # Are there default attributes associated with this scope?
+ def scope_attributes? # :nodoc:
+ current_scope || default_scopes.any?
+ end
+
# Adds a class method for retrieving and querying objects. A \scope represents a narrowing of a database query,
# such as <tt>where(:color => :red).select('shirts.*').includes(:washing_instructions)</tt>.
#
diff --git a/activerecord/lib/active_record/nested_attributes.rb b/activerecord/lib/active_record/nested_attributes.rb
index f51fd21077..53617059d0 100644
--- a/activerecord/lib/active_record/nested_attributes.rb
+++ b/activerecord/lib/active_record/nested_attributes.rb
@@ -276,15 +276,15 @@ module ActiveRecord
type = (reflection.collection? ? :collection : :one_to_one)
- # def pirate_attributes=(attributes, assignment_opts = {})
- # assign_nested_attributes_for_one_to_one_association(:pirate, attributes, assignment_opts)
+ # 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
- def #{association_name}_attributes=(attributes, assignment_opts = {})
- assign_nested_attributes_for_#{type}_association(:#{association_name}, attributes, assignment_opts)
+ def #{association_name}_attributes=(attributes)
+ assign_nested_attributes_for_#{type}_association(:#{association_name}, attributes, mass_assignment_options)
end
eoruby
else
diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb
index 367a1be4d9..f425118f59 100644
--- a/activerecord/lib/active_record/persistence.rb
+++ b/activerecord/lib/active_record/persistence.rb
@@ -319,9 +319,7 @@ module ActiveRecord
# that a new instance, or one populated from a passed-in Hash, still has all the attributes
# that instances loaded from the database would.
def attributes_from_column_definition
- Hash[self.class.columns.map do |column|
- [column.name, column.default]
- end]
+ self.class.column_defaults.dup
end
end
end
diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake
index 83909b0766..399f3c5d03 100644
--- a/activerecord/lib/active_record/railties/databases.rake
+++ b/activerecord/lib/active_record/railties/databases.rake
@@ -377,8 +377,7 @@ db_namespace = namespace :db do
dbfile = abcs[Rails.env]['database'] || abcs[Rails.env]['dbfile']
`sqlite3 #{dbfile} .schema > db/#{Rails.env}_structure.sql`
when 'sqlserver'
- `scptxfr /s #{abcs[Rails.env]['host']} /d #{abcs[Rails.env]['database']} /I /f db\\#{Rails.env}_structure.sql /q /A /r`
- `scptxfr /s #{abcs[Rails.env]['host']} /d #{abcs[Rails.env]['database']} /I /F db\ /q /A /r`
+ `smoscript -s #{abcs[Rails.env]['host']} -d #{abcs[Rails.env]['database']} -u #{abcs[Rails.env]['username']} -p #{abcs[Rails.env]['password']} -f db\\#{Rails.env}_structure.sql -A -U`
when "firebird"
set_firebird_env(abcs[Rails.env])
db_string = firebird_db_string(abcs[Rails.env])
@@ -423,7 +422,7 @@ db_namespace = namespace :db do
dbfile = abcs['test']['database'] || abcs['test']['dbfile']
`sqlite3 #{dbfile} < #{Rails.root}/db/#{Rails.env}_structure.sql`
when 'sqlserver'
- `osql -E -S #{abcs['test']['host']} -d #{abcs['test']['database']} -i db\\#{Rails.env}_structure.sql`
+ `sqlcmd -S #{abcs['test']['host']} -d #{abcs['test']['database']} -U #{abcs['test']['username']} -P #{abcs['test']['password']} -i db\\#{Rails.env}_structure.sql`
when 'oci', 'oracle'
ActiveRecord::Base.establish_connection(:test)
IO.readlines("#{Rails.root}/db/#{Rails.env}_structure.sql").join.split(";\n\n").each do |ddl|
@@ -453,9 +452,11 @@ db_namespace = namespace :db do
dbfile = abcs['test']['database'] || abcs['test']['dbfile']
File.delete(dbfile) if File.exist?(dbfile)
when 'sqlserver'
- dropfkscript = "#{abcs['test']['host']}.#{abcs['test']['database']}.DP1".gsub(/\\/,'-')
- `osql -E -S #{abcs['test']['host']} -d #{abcs['test']['database']} -i db\\#{dropfkscript}`
- `osql -E -S #{abcs['test']['host']} -d #{abcs['test']['database']} -i db\\#{Rails.env}_structure.sql`
+ test = abcs.deep_dup['test']
+ test_database = test['database']
+ test['database'] = 'master'
+ ActiveRecord::Base.establish_connection(test)
+ ActiveRecord::Base.connection.recreate_database!(test_database)
when "oci", "oracle"
ActiveRecord::Base.establish_connection(:test)
ActiveRecord::Base.connection.structure_drop.split(";\n\n").each do |ddl|
diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb
index 6df473d011..a2324039cf 100644
--- a/activerecord/lib/active_record/reflection.rb
+++ b/activerecord/lib/active_record/reflection.rb
@@ -80,12 +80,6 @@ module ActiveRecord
# Abstract base class for AggregateReflection and AssociationReflection. Objects of
# AggregateReflection and AssociationReflection are returned by the Reflection::ClassMethods.
class MacroReflection
- attr_reader :active_record
-
- def initialize(macro, name, options, active_record)
- @macro, @name, @options, @active_record = macro, name, options, active_record
- end
-
# Returns the name of the macro.
#
# <tt>composed_of :balance, :class_name => 'Money'</tt> returns <tt>:balance</tt>
@@ -104,6 +98,19 @@ module ActiveRecord
# <tt>has_many :clients</tt> returns +{}+
attr_reader :options
+ attr_reader :active_record
+
+ attr_reader :plural_name # :nodoc:
+
+ def initialize(macro, name, options, active_record)
+ @macro = macro
+ @name = name
+ @options = options
+ @active_record = active_record
+ @plural_name = active_record.pluralize_table_names ?
+ name.to_s.pluralize : name.to_s
+ end
+
# Returns the class for the macro.
#
# <tt>composed_of :balance, :class_name => 'Money'</tt> returns the Money class
@@ -123,7 +130,11 @@ module ActiveRecord
# Returns +true+ if +self+ and +other_aggregation+ have the same +name+ attribute, +active_record+ attribute,
# and +other_aggregation+ has an options hash assigned to it.
def ==(other_aggregation)
- other_aggregation.kind_of?(self.class) && name == other_aggregation.name && other_aggregation.options && active_record == other_aggregation.active_record
+ super ||
+ other_aggregation.kind_of?(self.class) &&
+ name == other_aggregation.name &&
+ other_aggregation.options &&
+ active_record == other_aggregation.active_record
end
def sanitized_conditions #:nodoc:
@@ -168,25 +179,8 @@ module ActiveRecord
# Returns a new, unsaved instance of the associated class. +options+ will
# be passed to the class's constructor.
- def build_association(*options)
- klass.new(*options)
- end
-
- # Creates a new instance of the associated class, and immediately saves it
- # with ActiveRecord::Base#save. +options+ will be passed to the class's
- # creation method. Returns the newly created object.
- def create_association(*options)
- klass.create(*options)
- end
-
- # Creates a new instance of the associated class, and immediately saves it
- # with ActiveRecord::Base#save!. +options+ will be passed to the class's
- # creation method. If the created record doesn't pass validations, then an
- # exception will be raised.
- #
- # Returns the newly created object.
- def create_association!(*options)
- klass.create!(*options)
+ def build_association(*options, &block)
+ klass.new(*options, &block)
end
def table_name
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index 317af8a15d..9cd146b857 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -6,7 +6,7 @@ module ActiveRecord
JoinOperation = Struct.new(:relation, :join_class, :on)
ASSOCIATION_METHODS = [:includes, :eager_load, :preload]
MULTI_VALUE_METHODS = [:select, :group, :order, :joins, :where, :having, :bind]
- SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :create_with, :from, :reorder, :reverse_order]
+ SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :from, :reorder, :reverse_order]
include FinderMethods, Calculations, SpawnMethods, QueryMethods, Batches
@@ -29,6 +29,7 @@ module ActiveRecord
SINGLE_VALUE_METHODS.each {|v| instance_variable_set(:"@#{v}_value", nil)}
(ASSOCIATION_METHODS + MULTI_VALUE_METHODS).each {|v| instance_variable_set(:"@#{v}_values", [])}
@extensions = []
+ @create_with_value = {}
end
def insert(values)
@@ -403,7 +404,7 @@ module ActiveRecord
end
def scope_for_create
- @scope_for_create ||= where_values_hash.merge(@create_with_value || {})
+ @scope_for_create ||= where_values_hash.merge(create_with_value)
end
def eager_loading?
diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb
index aabe5c269b..9c5f603c01 100644
--- a/activerecord/lib/active_record/relation/calculations.rb
+++ b/activerecord/lib/active_record/relation/calculations.rb
@@ -146,10 +146,16 @@ module ActiveRecord
if options.except(:distinct).present?
apply_finder_options(options.except(:distinct)).calculate(operation, column_name, :distinct => options[:distinct])
else
- if eager_loading? || (includes_values.present? && references_eager_loaded_tables?)
- construct_relation_for_association_calculations.calculate(operation, column_name, options)
+ relation = with_default_scope
+
+ if relation.equal?(self)
+ if eager_loading? || (includes_values.present? && references_eager_loaded_tables?)
+ construct_relation_for_association_calculations.calculate(operation, column_name, options)
+ else
+ perform_calculation(operation, column_name, options)
+ end
else
- perform_calculation(operation, column_name, options)
+ relation.calculate(operation, column_name, options)
end
end
rescue ThrowResult
@@ -196,7 +202,7 @@ module ActiveRecord
def execute_simple_calculation(operation, column_name, distinct) #:nodoc:
# Postgresql doesn't like ORDER BY when there are no GROUP BY
- relation = with_default_scope.reorder(nil)
+ relation = reorder(nil)
if operation == "count" && (relation.limit_value || relation.offset_value)
# Shortcut when limit is zero.
@@ -245,7 +251,7 @@ module ActiveRecord
"#{field} AS #{aliaz}"
}
- relation = with_default_scope.except(:group).group(group.join(','))
+ relation = except(:group).group(group.join(','))
relation.select_values = select_values
calculated_data = @klass.connection.select_all(relation.to_sql)
diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb
index 7fbbefeea2..ec2e4d4dcd 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -137,7 +137,7 @@ module ActiveRecord
def create_with(value)
relation = clone
- relation.create_with_value = value && (@create_with_value || {}).merge(value)
+ relation.create_with_value = value ? create_with_value.merge(value) : {}
relation
end
@@ -307,7 +307,7 @@ module ActiveRecord
order_query.map do |o|
case o
- when Arel::Nodes::Ordering
+ when Arel::Nodes::Ascending, Arel::Nodes::Descending
o.reverse
when String, Symbol
o.to_s.split(',').collect do |s|
diff --git a/activerecord/lib/active_record/relation/spawn_methods.rb b/activerecord/lib/active_record/relation/spawn_methods.rb
index 69706b5ead..ba882beca9 100644
--- a/activerecord/lib/active_record/relation/spawn_methods.rb
+++ b/activerecord/lib/active_record/relation/spawn_methods.rb
@@ -55,7 +55,7 @@ module ActiveRecord
merged_relation.lock_value = r.lock_value unless merged_relation.lock_value
- merged_relation = merged_relation.create_with(r.create_with_value) if r.create_with_value
+ merged_relation = merged_relation.create_with(r.create_with_value) unless r.create_with_value.empty?
# Apply scope extension modules
merged_relation.send :apply_modules, r.extensions
diff --git a/activerecord/lib/active_record/version.rb b/activerecord/lib/active_record/version.rb
index 43fe1cdee5..838aa8fb1e 100644
--- a/activerecord/lib/active_record/version.rb
+++ b/activerecord/lib/active_record/version.rb
@@ -1,9 +1,9 @@
module ActiveRecord
module VERSION #:nodoc:
MAJOR = 3
- MINOR = 1
+ MINOR = 2
TINY = 0
- PRE = "rc1"
+ PRE = "beta"
STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
end