aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib
diff options
context:
space:
mode:
authorJon Leighton <j@jonathanleighton.com>2010-09-30 23:29:23 +0100
committerJon Leighton <j@jonathanleighton.com>2010-09-30 23:29:23 +0100
commit704961ce688f5bc1942529f44ea6b00014ef8378 (patch)
treeb951112aed4914cdc4203bca6e810a7b71d37e82 /activerecord/lib
parentb689834bcf2730353d066277f43047f10abb8d30 (diff)
parent91deff08c940f16ed149e7628694faff0393fe0a (diff)
downloadrails-704961ce688f5bc1942529f44ea6b00014ef8378.tar.gz
rails-704961ce688f5bc1942529f44ea6b00014ef8378.tar.bz2
rails-704961ce688f5bc1942529f44ea6b00014ef8378.zip
Merge branch 'master' into nested_has_many_through_2
Diffstat (limited to 'activerecord/lib')
-rw-r--r--activerecord/lib/active_record/association_preload.rb6
-rw-r--r--activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb2
-rw-r--r--activerecord/lib/active_record/base.rb22
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb20
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb18
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb53
-rw-r--r--activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb7
-rw-r--r--activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb4
-rw-r--r--activerecord/lib/active_record/dynamic_finder_match.rb37
-rw-r--r--activerecord/lib/active_record/dynamic_scope_match.rb21
-rw-r--r--activerecord/lib/active_record/fixtures.rb8
-rw-r--r--activerecord/lib/active_record/nested_attributes.rb7
-rw-r--r--activerecord/lib/active_record/railtie.rb2
-rw-r--r--activerecord/lib/active_record/railties/databases.rake4
-rw-r--r--activerecord/lib/active_record/relation.rb15
-rw-r--r--activerecord/lib/active_record/relation/calculations.rb17
-rw-r--r--activerecord/lib/active_record/relation/query_methods.rb58
-rw-r--r--activerecord/lib/active_record/serialization.rb2
19 files changed, 139 insertions, 166 deletions
diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb
index 715c868598..e6b367790b 100644
--- a/activerecord/lib/active_record/association_preload.rb
+++ b/activerecord/lib/active_record/association_preload.rb
@@ -321,14 +321,14 @@ module ActiveRecord
klasses_and_ids[reflection.klass.name] = id_map unless id_map.empty?
end
- klasses_and_ids.each do |klass_name, id_map|
+ klasses_and_ids.each do |klass_name, _id_map|
klass = klass_name.constantize
table_name = klass.quoted_table_name
primary_key = reflection.options[:primary_key] || klass.primary_key
column_type = klass.columns.detect{|c| c.name == primary_key}.type
- ids = id_map.keys.map do |id|
+ ids = _id_map.keys.map do |id|
if column_type == :integer
id.to_i
elsif column_type == :float
@@ -343,7 +343,7 @@ module ActiveRecord
associated_records = klass.unscoped.where([conditions, ids]).apply_finder_options(options.slice(:include, :select, :joins, :order)).to_a
- set_association_single_records(id_map, reflection.name, associated_records, primary_key)
+ set_association_single_records(_id_map, reflection.name, associated_records, primary_key)
end
end
diff --git a/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb b/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb
index 38454ec242..e429806b0c 100644
--- a/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb
+++ b/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb
@@ -39,7 +39,7 @@ module ActiveRecord
def set_inverse_instance(record, instance)
return if record.nil? || !we_can_set_the_inverse_on_this?(record)
inverse_relationship = @reflection.polymorphic_inverse_of(record.class)
- unless inverse_relationship.nil?
+ if inverse_relationship
record.send(:"set_#{inverse_relationship.name}_target", instance)
end
end
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index f5291b180e..2157a0aded 100644
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -1014,8 +1014,9 @@ module ActiveRecord #:nodoc:
end
def all_attributes_exists?(attribute_names)
- attribute_names = expand_attribute_names_for_aggregates(attribute_names)
- attribute_names.all? { |name| column_methods_hash.include?(name.to_sym) }
+ expand_attribute_names_for_aggregates(attribute_names).all? { |name|
+ column_methods_hash.include?(name.to_sym)
+ }
end
protected
@@ -1383,10 +1384,7 @@ MSG
ensure_proper_type
- if scope = self.class.send(:current_scoped_methods)
- create_with = scope.scope_for_create
- create_with.each { |att,value| self.send("#{att}=", value) } if create_with
- end
+ populate_with_current_scope_attributes
self.attributes = attributes unless attributes.nil?
result = yield self if block_given?
@@ -1415,10 +1413,7 @@ MSG
@new_record = true
ensure_proper_type
- if scope = self.class.send(:current_scoped_methods)
- create_with = scope.scope_for_create
- create_with.each { |att,value| self.send("#{att}=", value) } if create_with
- end
+ populate_with_current_scope_attributes
end
# Returns a String, which Action Pack uses for constructing an URL to this
@@ -1807,6 +1802,13 @@ MSG
return string unless string.is_a?(String) && string =~ /^---/
YAML::load(string) rescue string
end
+
+ def populate_with_current_scope_attributes
+ if scope = self.class.send(:current_scoped_methods)
+ create_with = scope.scope_for_create
+ create_with.each { |att,value| self.respond_to?(:"#{att}=") && self.send("#{att}=", value) } if create_with
+ end
+ end
end
Base.class_eval do
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 25432e9985..646a78622c 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
@@ -35,7 +35,7 @@ module ActiveRecord
undef_method :select_rows
# Executes the SQL statement in the context of this connection.
- def execute(sql, name = nil, skip_logging = false)
+ def execute(sql, name = nil)
end
undef_method :execute
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
index 84fc4c03f9..6480aeb171 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
@@ -318,21 +318,13 @@ module ActiveRecord
@base = base
end
- #Handles non supported datatypes - e.g. XML
- def method_missing(symbol, *args)
- if symbol.to_s == 'xml'
- xml_column_fallback(args)
- else
- super
- end
- end
+ def xml(*args)
+ raise NotImplementedError unless %w{
+ sqlite mysql mysql2
+ }.include? @base.adapter_name.downcase
- def xml_column_fallback(*args)
- case @base.adapter_name.downcase
- when 'sqlite', 'mysql'
- options = args.extract_options!
- column(args[0], :text, options)
- end
+ options = args.extract_options!
+ column(args[0], :text, options)
end
# Appends a primary key definition to the table definition.
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
index 310423bb20..4e770c37da 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
@@ -151,10 +151,10 @@ module ActiveRecord
#
# See also TableDefinition#column for details on how to create columns.
def create_table(table_name, options = {})
- table_definition = TableDefinition.new(self)
- table_definition.primary_key(options[:primary_key] || Base.get_primary_key(table_name.to_s.singularize)) unless options[:id] == false
+ td = table_definition
+ td.primary_key(options[:primary_key] || Base.get_primary_key(table_name.to_s.singularize)) unless options[:id] == false
- yield table_definition if block_given?
+ yield td if block_given?
if options[:force] && table_exists?(table_name)
drop_table(table_name, options)
@@ -162,7 +162,7 @@ module ActiveRecord
create_sql = "CREATE#{' TEMPORARY' if options[:temporary]} TABLE "
create_sql << "#{quote_table_name(table_name)} ("
- create_sql << table_definition.to_sql
+ create_sql << td.to_sql
create_sql << ") #{options[:options]}"
execute create_sql
end
@@ -327,14 +327,12 @@ module ActiveRecord
#
# Note: SQLite doesn't support index length
def add_index(table_name, column_name, options = {})
- options[:name] = options[:name].to_s if options.key?(:name)
-
column_names = Array.wrap(column_name)
index_name = index_name(table_name, :column => column_names)
if Hash === options # legacy support, since this param was a string
index_type = options[:unique] ? "UNIQUE" : ""
- index_name = options[:name] || index_name
+ index_name = options[:name].to_s if options.key?(:name)
else
index_type = options
end
@@ -404,6 +402,7 @@ module ActiveRecord
# as there's no way to determine the correct answer in that case.
def index_name_exists?(table_name, index_name, default)
return default unless respond_to?(:indexes)
+ index_name = index_name.to_s
indexes(table_name).detect { |i| i.name == index_name }
end
@@ -535,6 +534,11 @@ module ActiveRecord
def options_include_default?(options)
options.include?(:default) && !(options[:null] == false && options[:default].nil?)
end
+
+ private
+ def table_definition
+ TableDefinition.new(self)
+ end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index 0a2bacdb84..194842a9a0 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -1,20 +1,19 @@
require 'active_record/connection_adapters/abstract_adapter'
require 'active_support/core_ext/kernel/requires'
require 'active_support/core_ext/object/blank'
+require 'pg'
module ActiveRecord
class Base
# Establishes a connection to the database that's used by all Active Record objects
def self.postgresql_connection(config) # :nodoc:
- require 'pg'
-
config = config.symbolize_keys
host = config[:host]
port = config[:port] || 5432
username = config[:username].to_s if config[:username]
password = config[:password].to_s if config[:password]
- if config.has_key?(:database)
+ if config.key?(:database)
database = config[:database]
else
raise ArgumentError, "No database specified. Missing argument: database."
@@ -27,12 +26,6 @@ module ActiveRecord
end
module ConnectionAdapters
- class TableDefinition
- def xml(*args)
- options = args.extract_options!
- column(args[0], 'xml', options)
- end
- end
# PostgreSQL-specific extensions to column definitions in a table.
class PostgreSQLColumn < Column #:nodoc:
# Instantiates a new PostgreSQL column definition in a table.
@@ -170,9 +163,7 @@ module ActiveRecord
end
end
end
- end
- module ConnectionAdapters
# The PostgreSQL adapter works both with the native C (http://ruby.scripting.ca/postgres/) and the pure
# Ruby (available both as gem and from http://rubyforge.org/frs/?group_id=234&release_id=1944) drivers.
#
@@ -192,10 +183,17 @@ module ActiveRecord
# * <tt>:allow_concurrency</tt> - If true, use async query methods so Ruby threads don't deadlock;
# otherwise, use blocking query methods.
class PostgreSQLAdapter < AbstractAdapter
- ADAPTER_NAME = 'PostgreSQL'.freeze
+ class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
+ def xml(*args)
+ options = args.extract_options!
+ column(args[0], 'xml', options)
+ end
+ end
+
+ ADAPTER_NAME = 'PostgreSQL'
NATIVE_DATABASE_TYPES = {
- :primary_key => "serial primary key".freeze,
+ :primary_key => "serial primary key",
:string => { :name => "character varying", :limit => 255 },
:text => { :name => "text" },
:integer => { :name => "integer" },
@@ -317,19 +315,22 @@ module ActiveRecord
def quote(value, column = nil) #:nodoc:
return super unless column
- if value.kind_of?(String) && column.type == :binary
- "'#{escape_bytea(value)}'"
- elsif value.kind_of?(String) && column.sql_type == 'xml'
- "xml '#{quote_string(value)}'"
- elsif value.kind_of?(Numeric) && column.sql_type == 'money'
+ case value
+ when Numeric
+ return super unless column.sql_type == 'money'
# Not truly string input, so doesn't require (or allow) escape string syntax.
"'#{value}'"
- elsif value.kind_of?(String) && column.sql_type =~ /^bit/
- case value
- when /^[01]*$/
- "B'#{value}'" # Bit-string notation
- when /^[0-9A-F]*$/i
- "X'#{value}'" # Hexadecimal notation
+ when String
+ case column.sql_type
+ when 'bytea' then "'#{escape_bytea(value)}'"
+ when 'xml' then "xml '#{quote_string(value)}'"
+ when /^bit/
+ case value
+ when /^[01]*$/ then "B'#{value}'" # Bit-string notation
+ when /^[0-9A-F]*$/i then "X'#{value}'" # Hexadecimal notation
+ end
+ else
+ super
end
else
super
@@ -1024,6 +1025,10 @@ module ActiveRecord
[match_data[1], (rest.length > 0 ? rest : nil)]
end
end
+
+ def table_definition
+ TableDefinition.new(self)
+ end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
index e5e92f2b1c..5ca1923d89 100644
--- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
@@ -1,4 +1,5 @@
require 'active_record/connection_adapters/sqlite_adapter'
+require 'sqlite3'
module ActiveRecord
class Base
@@ -20,16 +21,12 @@ module ActiveRecord
raise ArgumentError, 'adapter name should be "sqlite3"'
end
- unless self.class.const_defined?(:SQLite3)
- require_library_or_gem(config[:adapter])
- end
-
db = SQLite3::Database.new(
config[:database],
:results_as_hash => true
)
- db.busy_timeout(config[:timeout]) unless config[:timeout].nil?
+ db.busy_timeout(config[:timeout]) if config[:timeout]
ConnectionAdapters::SQLite3Adapter.new(db, logger, config)
end
diff --git a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb
index 0571e0cd14..c0cc7ba20d 100644
--- a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb
@@ -360,8 +360,8 @@ module ActiveRecord
end
def copy_table_contents(from, to, columns, rename = {}) #:nodoc:
- column_mappings = Hash[*columns.map {|name| [name, name]}.flatten]
- rename.inject(column_mappings) {|map, a| map[a.last] = a.first; map}
+ column_mappings = Hash[columns.map {|name| [name, name]}]
+ rename.each { |a| column_mappings[a.last] = a.first }
from_columns = columns(from).collect {|col| col.name}
columns = columns.find_all{|col| from_columns.include?(column_mappings[col])}
quoted_columns = columns.map { |col| quote_column_name(col) } * ','
diff --git a/activerecord/lib/active_record/dynamic_finder_match.rb b/activerecord/lib/active_record/dynamic_finder_match.rb
index 533bc331ae..b309df9b1b 100644
--- a/activerecord/lib/active_record/dynamic_finder_match.rb
+++ b/activerecord/lib/active_record/dynamic_finder_match.rb
@@ -6,40 +6,43 @@ module ActiveRecord
#
class DynamicFinderMatch
def self.match(method)
- df_match = self.new(method)
- df_match.finder ? df_match : nil
- end
-
- def initialize(method)
- @finder = :first
- @bang = false
- @instantiator = nil
+ finder = :first
+ bang = false
+ instantiator = nil
case method.to_s
- when /^find_(all_by|last_by|by)_([_a-zA-Z]\w*)$/
- @finder = :last if $1 == 'last_by'
- @finder = :all if $1 == 'all_by'
+ when /^find_(all_|last_)?by_([_a-zA-Z]\w*)$/
+ finder = :last if $1 == 'last_'
+ finder = :all if $1 == 'all_'
names = $2
when /^find_by_([_a-zA-Z]\w*)\!$/
- @bang = true
+ bang = true
names = $1
when /^find_or_(initialize|create)_by_([_a-zA-Z]\w*)$/
- @instantiator = $1 == 'initialize' ? :new : :create
+ instantiator = $1 == 'initialize' ? :new : :create
names = $2
else
- @finder = nil
+ return nil
end
- @attribute_names = names && names.split('_and_')
+
+ new(finder, instantiator, bang, names.split('_and_'))
+ end
+
+ def initialize(finder, instantiator, bang, attribute_names)
+ @finder = finder
+ @instantiator = instantiator
+ @bang = bang
+ @attribute_names = attribute_names
end
attr_reader :finder, :attribute_names, :instantiator
def finder?
- !@finder.nil? && @instantiator.nil?
+ @finder && !@instantiator
end
def instantiator?
- @finder == :first && !@instantiator.nil?
+ @finder == :first && @instantiator
end
def creator?
diff --git a/activerecord/lib/active_record/dynamic_scope_match.rb b/activerecord/lib/active_record/dynamic_scope_match.rb
index 61c3ea0e7f..c832e927d6 100644
--- a/activerecord/lib/active_record/dynamic_scope_match.rb
+++ b/activerecord/lib/active_record/dynamic_scope_match.rb
@@ -8,25 +8,16 @@ module ActiveRecord
# scope except that it's dynamic.
class DynamicScopeMatch
def self.match(method)
- ds_match = self.new(method)
- ds_match.scope ? ds_match : nil
+ return unless method.to_s =~ /^scoped_by_([_a-zA-Z]\w*)$/
+ new(true, $1 && $1.split('_and_'))
end
- def initialize(method)
- @scope = true
- case method.to_s
- when /^scoped_by_([_a-zA-Z]\w*)$/
- names = $1
- else
- @scope = nil
- end
- @attribute_names = names && names.split('_and_')
+ def initialize(scope, attribute_names)
+ @scope = scope
+ @attribute_names = attribute_names
end
attr_reader :scope, :attribute_names
-
- def scope?
- !@scope.nil?
- end
+ alias :scope? :scope
end
end
diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb
index 826031a3e3..6fb723f2f5 100644
--- a/activerecord/lib/active_record/fixtures.rb
+++ b/activerecord/lib/active_record/fixtures.rb
@@ -704,11 +704,9 @@ class Fixtures < (RUBY_VERSION < '1.9' ? YAML::Omap : Hash)
end
def read_yaml_fixture_files
- yaml_string = ""
- Dir["#{@fixture_path}/**/*.yml"].select { |f| test(?f, f) }.each do |subfixture_path|
- yaml_string << IO.read(subfixture_path)
- end
- yaml_string << IO.read(yaml_file_path)
+ yaml_string = (Dir["#{@fixture_path}/**/*.yml"].select { |f|
+ File.file?(f)
+ } + [yaml_file_path]).map { |file_path| IO.read(file_path) }.join
if yaml = parse_yaml_string(yaml_string)
# If the file is an ordered map, extract its children.
diff --git a/activerecord/lib/active_record/nested_attributes.rb b/activerecord/lib/active_record/nested_attributes.rb
index 7372ab3278..bdd940f3ee 100644
--- a/activerecord/lib/active_record/nested_attributes.rb
+++ b/activerecord/lib/active_record/nested_attributes.rb
@@ -377,7 +377,12 @@ module ActiveRecord
end
if attributes_collection.is_a? Hash
- attributes_collection = attributes_collection.sort_by { |index, _| index.to_i }.map { |_, attributes| attributes }
+ keys = attributes_collection.keys
+ attributes_collection = if keys.include?('id') || keys.include?(:id)
+ Array.wrap(attributes_collection)
+ else
+ attributes_collection.sort_by { |i, _| i.to_i }.map { |_, attributes| attributes }
+ end
end
association = send(association_name)
diff --git a/activerecord/lib/active_record/railtie.rb b/activerecord/lib/active_record/railtie.rb
index 94dda4e413..868fd6c3ff 100644
--- a/activerecord/lib/active_record/railtie.rb
+++ b/activerecord/lib/active_record/railtie.rb
@@ -13,7 +13,7 @@ module ActiveRecord
class Railtie < Rails::Railtie
config.active_record = ActiveSupport::OrderedOptions.new
- config.generators.orm :active_record, :migration => true,
+ config.app_generators.orm :active_record, :migration => true,
:timestamps => true
config.app_middleware.insert_after "::ActionDispatch::Callbacks",
diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake
index 12bfe3c738..58c705c8b2 100644
--- a/activerecord/lib/active_record/railties/databases.rake
+++ b/activerecord/lib/active_record/railties/databases.rake
@@ -108,7 +108,7 @@ namespace :db do
end
end
when 'postgresql'
- @encoding = config[:encoding] || ENV['CHARSET'] || 'utf8'
+ @encoding = config['encoding'] || ENV['CHARSET'] || 'utf8'
begin
ActiveRecord::Base.establish_connection(config.merge('database' => 'postgres', 'schema_search_path' => 'public'))
ActiveRecord::Base.connection.create_database(config['database'], config.merge('encoding' => @encoding))
@@ -390,7 +390,7 @@ namespace :db do
db_string = firebird_db_string(abcs[Rails.env])
sh "isql -a #{db_string} > #{Rails.root}/db/#{Rails.env}_structure.sql"
else
- raise "Task not supported by '#{abcs["test"]["adapter"]}'"
+ raise "Task not supported by '#{abcs[Rails.env]["adapter"]}'"
end
if ActiveRecord::Base.connection.supports_migrations?
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index 478f1e8ef1..04ba5b291e 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -326,7 +326,11 @@ module ActiveRecord
def scope_for_create
@scope_for_create ||= begin
- @create_with_value || where_values_hash
+ if @create_with_value
+ @create_with_value.reverse_merge(where_values_hash)
+ else
+ where_values_hash
+ end
end
end
@@ -358,15 +362,6 @@ module ActiveRecord
scoping { @klass.send(method, *args, &block) }
elsif arel.respond_to?(method)
arel.send(method, *args, &block)
- elsif match = DynamicFinderMatch.match(method)
- attributes = match.attribute_names
- super unless @klass.send(:all_attributes_exists?, attributes)
-
- if match.finder?
- find_by_attributes(match, attributes, *args)
- elsif match.instantiator?
- find_or_instantiator_by_attributes(match, attributes, *args, &block)
- end
else
super
end
diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb
index 12a2c6aec3..03862c78e4 100644
--- a/activerecord/lib/active_record/relation/calculations.rb
+++ b/activerecord/lib/active_record/relation/calculations.rb
@@ -191,7 +191,11 @@ module ActiveRecord
end
# Postgresql doesn't like ORDER BY when there are no GROUP BY
- relation = except(:order).select(operation == 'count' ? column.count(distinct) : column.send(operation))
+ relation = except(:order)
+ select_value = operation == 'count' ? column.count(distinct) : column.send(operation)
+
+ relation.select_values = [select_value]
+
type_cast_calculated_value(@klass.connection.select_value(relation.to_sql), column_for(column_name), operation)
end
@@ -208,21 +212,22 @@ module ActiveRecord
aggregate_alias = column_alias_for(operation, column_name)
select_statement = if operation == 'count' && column_name == :all
- "COUNT(*) AS count_all"
+ ["COUNT(*) AS count_all"]
else
- Arel::Attribute.new(@klass.unscoped.table, column_name).send(operation).as(aggregate_alias).to_sql
+ [Arel::Attribute.new(@klass.unscoped.table, column_name).send(operation).as(aggregate_alias)]
end
- select_statement << ", #{group_field} AS #{group_alias}"
+ select_statement << "#{group_field} AS #{group_alias}"
- relation = except(:group).select(select_statement).group(group)
+ relation = except(:group).group(group)
+ relation.select_values = select_statement
calculated_data = @klass.connection.select_all(relation.to_sql)
if association
key_ids = calculated_data.collect { |row| row[group_alias] }
key_records = association.klass.base_class.find(key_ids)
- key_records = key_records.inject({}) { |hsh, r| hsh.merge(r.id => r) }
+ key_records = Hash[key_records.map { |r| [r.id, r] }]
end
ActiveSupport::OrderedHash[calculated_data.map do |row|
diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb
index 6a33edeb97..2e0a2effc2 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -36,7 +36,7 @@ module ActiveRecord
to_a.select {|*block_args| value.call(*block_args) }
else
relation = clone
- relation.select_values += [value]
+ relation.select_values += Array.wrap(value)
relation
end
end
@@ -135,14 +135,13 @@ module ActiveRecord
end
def reverse_order
- order_clause = arel.order_clauses.join(', ')
- relation = except(:order)
+ order_clause = arel.order_clauses
- order = order_clause.blank? ?
+ order = order_clause.empty? ?
"#{@klass.table_name}.#{@klass.primary_key} DESC" :
- reverse_sql_order(order_clause)
+ reverse_sql_order(order_clause).join(', ')
- relation.order(Arel::SqlLiteral.new(order))
+ except(:order).order(Arel::SqlLiteral.new(order))
end
def arel
@@ -150,7 +149,7 @@ module ActiveRecord
end
def custom_join_sql(*joins)
- arel = table
+ arel = table.select_manager
joins.each do |join|
next if join.blank?
@@ -158,16 +157,13 @@ module ActiveRecord
@implicit_readonly = true
case join
- when Hash, Array, Symbol
- if array_of_strings?(join)
- join_string = join.join(' ')
- arel = arel.join(Arel::SqlLiteral.new(join_string))
- end
+ when Array
+ join = Arel.sql(join.join(' ')) if array_of_strings?(join)
when String
- arel = arel.join(Arel::SqlLiteral.new(join))
- else
- arel = arel.join(join)
+ join = Arel.sql(join)
end
+
+ arel.join(join)
end
arel.joins(arel)
@@ -179,13 +175,8 @@ module ActiveRecord
arel = build_joins(arel, @joins_values) unless @joins_values.empty?
(@where_values - ['']).uniq.each do |where|
- case where
- when Arel::SqlLiteral
- arel = arel.where(where)
- else
- sql = where.is_a?(String) ? where : where.to_sql
- arel = arel.where(Arel::SqlLiteral.new("(#{sql})"))
- end
+ where = Arel.sql(where) if String === where
+ arel = arel.where(Arel::Nodes::Grouping.new(where))
end
arel = arel.having(*@having_values.uniq.reject{|h| h.blank?}) unless @having_values.empty?
@@ -260,16 +251,7 @@ module ActiveRecord
def build_select(arel, selects)
unless selects.empty?
@implicit_readonly = false
- # TODO: fix this ugly hack, we should refactor the callers to get an Arel compatible array.
- # Before this change we were passing to Arel the last element only, and Arel is capable of handling an array
- case select = selects.last
- when Arel::Expression, Arel::SqlLiteral
- arel.project(select)
- when /^COUNT\(/
- arel.project(Arel::SqlLiteral.new(select))
- else
- arel.project(*selects)
- end
+ arel.project(*selects)
else
arel.project(Arel::SqlLiteral.new(@klass.quoted_table_name + '.*'))
end
@@ -283,15 +265,9 @@ module ActiveRecord
end
def reverse_sql_order(order_query)
- order_query.split(',').each { |s|
- if s.match(/\s(asc|ASC)$/)
- s.gsub!(/\s(asc|ASC)$/, ' DESC')
- elsif s.match(/\s(desc|DESC)$/)
- s.gsub!(/\s(desc|DESC)$/, ' ASC')
- else
- s.concat(' DESC')
- end
- }.join(',')
+ order_query.join(', ').split(',').collect do |s|
+ s.gsub!(/\sasc\Z/i, ' DESC') || s.gsub!(/\sdesc\Z/i, ' ASC') || s.concat(' DESC')
+ end
end
def array_of_strings?(o)
diff --git a/activerecord/lib/active_record/serialization.rb b/activerecord/lib/active_record/serialization.rb
index ad3f7afd6f..398eb1534a 100644
--- a/activerecord/lib/active_record/serialization.rb
+++ b/activerecord/lib/active_record/serialization.rb
@@ -45,7 +45,7 @@ module ActiveRecord #:nodoc:
send(association)
end
- unless records.nil?
+ if records
association_options = include_has_options ? include_associations[association] : base_only_or_except
opts = options.merge(association_options)
yield(association, records, opts)