aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Gemfile3
-rw-r--r--actionpack/lib/action_controller/metal/strong_parameters.rb7
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb8
-rw-r--r--actionpack/test/abstract_unit.rb2
-rw-r--r--actionpack/test/controller/parameters/parameters_permit_test.rb3
-rw-r--r--activerecord/CHANGELOG.md19
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb3
-rw-r--r--activerecord/lib/active_record/connection_adapters/column.rb1
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/cast.rb36
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid.rb76
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb19
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb8
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb50
-rw-r--r--activerecord/lib/active_record/relation/predicate_builder.rb4
-rw-r--r--activerecord/lib/active_record/relation/query_methods.rb5
-rw-r--r--activerecord/test/cases/adapters/postgresql/datatype_test.rb302
-rw-r--r--activerecord/test/cases/adapters/postgresql/intrange_test.rb106
-rw-r--r--activerecord/test/cases/associations/habtm_join_table_test.rb35
-rw-r--r--activerecord/test/cases/helper.rb2
-rw-r--r--activerecord/test/cases/relation/where_test.rb15
-rw-r--r--activerecord/test/models/author.rb12
-rw-r--r--activerecord/test/models/category.rb5
-rw-r--r--activerecord/test/models/comment.rb6
-rw-r--r--activerecord/test/models/post.rb18
-rw-r--r--activerecord/test/models/project.rb3
-rw-r--r--activerecord/test/models/topic.rb1
-rw-r--r--activerecord/test/schema/postgresql_specific_schema.rb26
-rw-r--r--activesupport/test/abstract_unit.rb2
-rw-r--r--railties/CHANGELOG.md14
-rw-r--r--railties/lib/rails/engine.rb12
-rw-r--r--railties/lib/rails/engine/configuration.rb24
-rw-r--r--railties/lib/rails/generators/rails/app/app_generator.rb2
-rw-r--r--railties/lib/rails/paths.rb44
-rw-r--r--railties/railties.gemspec2
-rw-r--r--railties/test/application/initializers/load_path_test.rb2
-rw-r--r--railties/test/application/paths_test.rb10
-rw-r--r--railties/test/generators/app_generator_test.rb5
-rw-r--r--railties/test/paths_test.rb56
39 files changed, 601 insertions, 349 deletions
diff --git a/Gemfile b/Gemfile
index 122c108a07..09d0f502ce 100644
--- a/Gemfile
+++ b/Gemfile
@@ -12,9 +12,6 @@ gem 'jquery-rails', '~> 2.2.0', github: 'rails/jquery-rails'
gem 'turbolinks'
gem 'coffee-rails', github: 'rails/coffee-rails'
-# TODO: Release thor
-gem 'thor', github: 'wycats/thor', branch: 'master'
-
gem 'activerecord-deprecated_finders', github: 'rails/activerecord-deprecated_finders', branch: 'master'
# Needed for compiling the ActionDispatch::Journey parser
diff --git a/actionpack/lib/action_controller/metal/strong_parameters.rb b/actionpack/lib/action_controller/metal/strong_parameters.rb
index d028c7d8c4..7e720ca6f5 100644
--- a/actionpack/lib/action_controller/metal/strong_parameters.rb
+++ b/actionpack/lib/action_controller/metal/strong_parameters.rb
@@ -1,6 +1,7 @@
require 'active_support/core_ext/hash/indifferent_access'
require 'active_support/core_ext/array/wrap'
require 'active_support/rescuable'
+require 'action_dispatch/http/upload'
module ActionController
# Raised when a required parameter is missing.
@@ -190,8 +191,9 @@ module ActionController
#
# +:name+ passes it is a key of +params+ whose associated value is of type
# +String+, +Symbol+, +NilClass+, +Numeric+, +TrueClass+, +FalseClass+,
- # +Date+, +Time+, +DateTime+, +StringIO+, or +IO+. Otherwise, the key +:name+
- # is filtered out.
+ # +Date+, +Time+, +DateTime+, +StringIO+, +IO+, or
+ # +ActionDispatch::Http::UploadedFile+. Otherwise, the key +:name+ is
+ # filtered out.
#
# You may declare that the parameter should be an array of permitted scalars
# by mapping it to an empty array:
@@ -371,6 +373,7 @@ module ActionController
# DateTimes are Dates, we document the type but avoid the redundant check.
StringIO,
IO,
+ ActionDispatch::Http::UploadedFile,
]
def permitted_scalar?(value)
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
index c72310cca3..705314f8ab 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -122,14 +122,12 @@ module ActionDispatch
end
def helper_names
- self.module.instance_methods.map(&:to_s)
+ @helpers.map(&:to_s)
end
def clear!
@helpers.each do |helper|
- @module.module_eval do
- remove_possible_method helper
- end
+ @module.remove_possible_method helper
end
@routes.clear
@@ -185,8 +183,8 @@ module ActionDispatch
# foo_url(bar, baz, bang, sort_by: 'baz')
#
def define_url_helper(route, name, options)
+ @module.remove_possible_method name
@module.module_eval <<-END_EVAL, __FILE__, __LINE__ + 1
- remove_possible_method :#{name}
def #{name}(*args)
if #{optimize_helper?(route)} && args.size == #{route.required_parts.size} && !args.last.is_a?(Hash) && optimize_routes_generation?
options = #{options.inspect}
diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb
index bbcd289886..7157bccfb3 100644
--- a/actionpack/test/abstract_unit.rb
+++ b/actionpack/test/abstract_unit.rb
@@ -38,6 +38,8 @@ end
ActiveSupport::Dependencies.hook!
+Thread.abort_on_exception = true
+
# Show backtraces for deprecated behavior for quicker cleanup.
ActiveSupport::Deprecation.debug = true
diff --git a/actionpack/test/controller/parameters/parameters_permit_test.rb b/actionpack/test/controller/parameters/parameters_permit_test.rb
index 734662ae11..aadb142660 100644
--- a/actionpack/test/controller/parameters/parameters_permit_test.rb
+++ b/actionpack/test/controller/parameters/parameters_permit_test.rb
@@ -1,4 +1,5 @@
require 'abstract_unit'
+require 'action_dispatch/http/upload'
require 'action_controller/metal/strong_parameters'
class ParametersPermitTest < ActiveSupport::TestCase
@@ -31,7 +32,7 @@ class ParametersPermitTest < ActiveSupport::TestCase
values += [0, 1.0, 2**128, BigDecimal.new(1)]
values += [true, false]
values += [Date.today, Time.now, DateTime.now]
- values += [StringIO.new]
+ values += [STDOUT, StringIO.new, ActionDispatch::Http::UploadedFile.new(tempfile: __FILE__)]
values.each do |value|
params = ActionController::Parameters.new(id: value)
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index f1cca0ad76..278baee68f 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,5 +1,24 @@
## Rails 4.0.0 (unreleased) ##
+* PostgreSQL ranges type support. Includes: int4range, int8range,
+ numrange, tsrange, tstzrange, daterange
+
+ Ranges can be created with inclusive and exclusive bounds.
+
+ Example:
+
+ create_table :Room do |t|
+ t.daterange :availability
+ end
+
+ Room.create(availability: (Date.today..Float::INFINITY))
+ Room.first.availability # => Wed, 19 Sep 2012..Infinity
+
+ One thing to note: Range class does not support exclusive lower
+ bound.
+
+ *Alexander Grebennik*
+
* Added a state instance variable to each transaction. Will allow other objects
to know whether a transaction has been committed or rolled back.
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 3675184193..847d9da6e6 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
@@ -237,7 +237,7 @@ module ActiveRecord
@spec = spec
@checkout_timeout = spec.config[:checkout_timeout] || 5
- @dead_connection_timeout = spec.config[:dead_connection_timeout]
+ @dead_connection_timeout = spec.config[:dead_connection_timeout] || 5
@reaper = Reaper.new self, spec.config[:reaping_frequency]
@reaper.run
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb
index 9d6111b51e..fd5eaab9c9 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb
@@ -47,6 +47,9 @@ module ActiveRecord
value.to_s
when Date, DateTime, Time
"'#{value.to_s(:db)}'"
+ when Range
+ # infinity dumps as Infinity, which causes uninitialized constant error
+ value.inspect.gsub('Infinity', '::Float::INFINITY')
else
value.inspect
end
diff --git a/activerecord/lib/active_record/connection_adapters/column.rb b/activerecord/lib/active_record/connection_adapters/column.rb
index fb28ecb6cf..747331f3a1 100644
--- a/activerecord/lib/active_record/connection_adapters/column.rb
+++ b/activerecord/lib/active_record/connection_adapters/column.rb
@@ -126,7 +126,6 @@ module ActiveRecord
when :hstore then "#{klass}.string_to_hstore(#{var_name})"
when :inet, :cidr then "#{klass}.string_to_cidr(#{var_name})"
when :json then "#{klass}.string_to_json(#{var_name})"
- when :intrange then "#{klass}.string_to_intrange(#{var_name})"
else var_name
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb b/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb
index f7d734a2f1..3d8f0b575c 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb
@@ -62,6 +62,12 @@ module ActiveRecord
"{#{casted_values.join(',')}}"
end
+ def range_to_string(object)
+ from = object.begin.respond_to?(:infinite?) && object.begin.infinite? ? '' : object.begin
+ to = object.end.respond_to?(:infinite?) && object.end.infinite? ? '' : object.end
+ "[#{from},#{to}#{object.exclude_end? ? ')' : ']'}"
+ end
+
def string_to_json(string)
if String === string
ActiveSupport::JSON.decode(string)
@@ -92,36 +98,6 @@ module ActiveRecord
parse_pg_array(string).map{|val| oid.type_cast val}
end
- def string_to_intrange(string)
- if string.nil?
- nil
- elsif "empty" == string
- (nil..nil)
- elsif String === string && (matches = /^(\(|\[)([0-9]+),(\s?)([0-9]+)(\)|\])$/i.match(string))
- lower_bound = ("(" == matches[1] ? (matches[2].to_i + 1) : matches[2].to_i)
- upper_bound = (")" == matches[5] ? (matches[4].to_i - 1) : matches[4].to_i)
- (lower_bound..upper_bound)
- else
- string
- end
- end
-
- def intrange_to_string(object)
- if object.nil?
- nil
- elsif Range === object
- if [object.first, object.last].all? { |el| Integer === el }
- "[#{object.first.to_i},#{object.exclude_end? ? object.last.to_i : object.last.to_i + 1})"
- elsif [object.first, object.last].all? { |el| NilClass === el }
- "empty"
- else
- nil
- end
- else
- object
- end
- end
-
private
HstorePair = begin
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb
index 02c295983f..d90b9283ef 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb
@@ -78,6 +78,64 @@ module ActiveRecord
end
end
+ class Range < Type
+ attr_reader :subtype
+ def initialize(subtype)
+ @subtype = subtype
+ end
+
+ def exctract_bounds(value)
+ from, to = value[1..-2].split(',')
+ {
+ from: (value[1] == ',' || from == '-infinity') ? infinity(:negative => true) : from,
+ to: (value[-2] == ',' || to == 'infinity') ? infinity : to,
+ exclude_start: (value[0] == '('),
+ exclude_end: (value[-1] == ')')
+ }
+ end
+
+ def infinity(options = {})
+ ::Float::INFINITY * (options[:negative] ? -1 : 1)
+ end
+
+ def infinity?(value)
+ value.respond_to?(:infinite?) && value.infinite?
+ end
+
+ def to_integer(value)
+ infinity?(value) ? value : value.to_i
+ end
+
+ def type_cast(value)
+ return if value.nil? || value == 'empty'
+ return value if value.is_a?(::Range)
+
+ extracted = exctract_bounds(value)
+
+ case @subtype
+ when :date
+ from = ConnectionAdapters::Column.value_to_date(extracted[:from])
+ from -= 1.day if extracted[:exclude_start]
+ to = ConnectionAdapters::Column.value_to_date(extracted[:to])
+ when :decimal
+ from = BigDecimal.new(extracted[:from].to_s)
+ # FIXME: add exclude start for ::Range, same for timestamp ranges
+ to = BigDecimal.new(extracted[:to].to_s)
+ when :time
+ from = ConnectionAdapters::Column.string_to_time(extracted[:from])
+ to = ConnectionAdapters::Column.string_to_time(extracted[:to])
+ when :integer
+ from = to_integer(extracted[:from]) rescue value ? 1 : 0
+ from -= 1 if extracted[:exclude_start]
+ to = to_integer(extracted[:to]) rescue value ? 1 : 0
+ else
+ return value
+ end
+
+ ::Range.new(from, to, extracted[:exclude_end])
+ end
+ end
+
class Integer < Type
def type_cast(value)
return if value.nil?
@@ -168,14 +226,6 @@ module ActiveRecord
end
end
- class IntRange < Type
- def type_cast(value)
- return if value.nil?
-
- ConnectionAdapters::PostgreSQLColumn.string_to_intrange value
- end
- end
-
class TypeMap
def initialize
@mapping = {}
@@ -241,6 +291,13 @@ module ActiveRecord
alias_type 'int8', 'int2'
alias_type 'oid', 'int2'
+ register_type 'daterange', OID::Range.new(:date)
+ register_type 'numrange', OID::Range.new(:decimal)
+ register_type 'tsrange', OID::Range.new(:time)
+ register_type 'int4range', OID::Range.new(:integer)
+ alias_type 'tstzrange', 'tsrange'
+ alias_type 'int8range', 'int4range'
+
register_type 'numeric', OID::Decimal.new
register_type 'text', OID::Identity.new
alias_type 'varchar', 'text'
@@ -278,9 +335,6 @@ module ActiveRecord
register_type 'json', OID::Json.new
register_type 'ltree', OID::Identity.new
- register_type 'int4range', OID::IntRange.new
- alias_type 'int8range', 'int4range'
-
register_type 'cidr', OID::Cidr.new
alias_type 'inet', 'cidr'
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb
index c2fcef94da..791b032023 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb
@@ -19,6 +19,12 @@ module ActiveRecord
return super unless column
case value
+ when Range
+ if /range$/ =~ column.sql_type
+ "'#{PostgreSQLColumn.range_to_string(value)}'::#{column.sql_type}"
+ else
+ super
+ end
when Array
if column.array
"'#{PostgreSQLColumn.array_to_string(value, column, self)}'"
@@ -31,11 +37,6 @@ module ActiveRecord
when 'json' then super(PostgreSQLColumn.json_to_string(value), column)
else super
end
- when Range
- case column.sql_type
- when 'int4range', 'int8range' then super(PostgreSQLColumn.intrange_to_string(value), column)
- else super
- end
when IPAddr
case column.sql_type
when 'inet', 'cidr' then super(PostgreSQLColumn.cidr_to_string(value), column)
@@ -74,6 +75,9 @@ module ActiveRecord
return super(value, column) unless column
case value
+ when Range
+ return super(value, column) unless /range$/ =~ column.sql_type
+ PostgreSQLColumn.range_to_string(value)
when NilClass
if column.array && array_member
'NULL'
@@ -94,11 +98,6 @@ module ActiveRecord
when 'json' then PostgreSQLColumn.json_to_string(value)
else super(value, column)
end
- when Range
- case column.sql_type
- when 'int4range', 'int8range' then PostgreSQLColumn.intrange_to_string(value)
- else super(value, column)
- end
when IPAddr
return super(value, column) unless ['inet','cidr'].include? column.sql_type
PostgreSQLColumn.cidr_to_string(value)
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
index 8c68576bdc..73ca2c8e61 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
@@ -417,14 +417,6 @@ module ActiveRecord
when 0..6; "timestamp(#{precision})"
else raise(ActiveRecordError, "No timestamp type has precision of #{precision}. The allowed range of precision is from 0 to 6")
end
- when 'intrange'
- return 'int4range' unless limit
-
- case limit
- when 1..4; 'int4range'
- when 5..8; 'int8range'
- else raise(ActiveRecordError, "No range type has byte size #{limit}. Use a numeric with precision 0 instead.")
- end
else
super
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index b1b0467379..209553b26e 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -77,6 +77,8 @@ module ActiveRecord
return default unless default
case default
+ when /\A'(.*)'::(num|date|tstz|ts|int4|int8)range\z/m
+ $1
# Numeric types
when /\A\(?(-?\d+(\.\d*)?\)?)\z/
$1
@@ -117,9 +119,6 @@ module ActiveRecord
# JSON
when /\A'(.*)'::json\z/
$1
- # int4range, int8range
- when /\A'(.*)'::int(4|8)range\z/
- $1
# Object identifier types
when /\A-?\d+\z/
$1
@@ -220,12 +219,11 @@ module ActiveRecord
# JSON type
when 'json'
:json
- # int4range, int8range types
- when 'int4range', 'int8range'
- :intrange
# Small and big integer types
when /^(?:small|big)int$/
:integer
+ when /(num|date|tstz|ts|int4|int8)range$/
+ field_type.to_sym
# Pass through all types that are not specific to PostgreSQL.
else
super
@@ -276,6 +274,30 @@ module ActiveRecord
column(args[0], 'tsvector', options)
end
+ def int4range(name, options = {})
+ column(name, 'int4range', options)
+ end
+
+ def int8range(name, options = {})
+ column(name, 'int8range', options)
+ end
+
+ def tsrange(name, options = {})
+ column(name, 'tsrange', options)
+ end
+
+ def tstzrange(name, options = {})
+ column(name, 'tstzrange', options)
+ end
+
+ def numrange(name, options = {})
+ column(name, 'numrange', options)
+ end
+
+ def daterange(name, options = {})
+ column(name, 'daterange', options)
+ end
+
def hstore(name, options = {})
column(name, 'hstore', options)
end
@@ -304,10 +326,6 @@ module ActiveRecord
column(name, 'json', options)
end
- def intrange(name, options = {})
- column(name, 'intrange', options)
- end
-
def column(name, type = nil, options = {})
super
column = self[name]
@@ -339,6 +357,12 @@ module ActiveRecord
timestamp: { name: "timestamp" },
time: { name: "time" },
date: { name: "date" },
+ daterange: { name: "daterange" },
+ numrange: { name: "numrange" },
+ tsrange: { name: "tsrange" },
+ tstzrange: { name: "tstzrange" },
+ int4range: { name: "int4range" },
+ int8range: { name: "int8range" },
binary: { name: "bytea" },
boolean: { name: "boolean" },
xml: { name: "xml" },
@@ -349,7 +373,6 @@ module ActiveRecord
macaddr: { name: "macaddr" },
uuid: { name: "uuid" },
json: { name: "json" },
- intrange: { name: "int4range" },
ltree: { name: "ltree" }
}
@@ -552,6 +575,11 @@ module ActiveRecord
true
end
+ # Range datatypes weren't introduced until PostgreSQL 9.2
+ def supports_ranges?
+ postgresql_version >= 90200
+ end
+
# Returns the configured supported identifier length supported by PostgreSQL
def table_alias_length
@table_alias_length ||= query('SHOW max_identifier_length', 'SCHEMA')[0][0].to_i
diff --git a/activerecord/lib/active_record/relation/predicate_builder.rb b/activerecord/lib/active_record/relation/predicate_builder.rb
index 883d25d80b..537ebbef28 100644
--- a/activerecord/lib/active_record/relation/predicate_builder.rb
+++ b/activerecord/lib/active_record/relation/predicate_builder.rb
@@ -58,7 +58,7 @@ module ActiveRecord
key
else
key = key.to_s
- key.split('.').first.to_sym if key.include?('.')
+ key.split('.').first if key.include?('.')
end
end.compact
end
@@ -66,7 +66,7 @@ module ActiveRecord
private
def self.build(attribute, value)
case value
- when Array, ActiveRecord::Associations::CollectionProxy
+ when Array
values = value.to_a.map {|x| x.is_a?(Base) ? x.id : x}
ranges, values = values.partition {|v| v.is_a?(Range)}
diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb
index 46c0d6206f..42849d6bc9 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -764,6 +764,11 @@ module ActiveRecord
[@klass.send(:sanitize_sql, other.empty? ? opts : ([opts] + other))]
when Hash
attributes = @klass.send(:expand_hash_conditions_for_aggregates, opts)
+
+ attributes.values.grep(ActiveRecord::Relation) do |rel|
+ self.bind_values += rel.bind_values
+ end
+
PredicateBuilder.build_from_hash(klass, attributes, table)
else
[opts]
diff --git a/activerecord/test/cases/adapters/postgresql/datatype_test.rb b/activerecord/test/cases/adapters/postgresql/datatype_test.rb
index 2254be8612..7351ed9013 100644
--- a/activerecord/test/cases/adapters/postgresql/datatype_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/datatype_test.rb
@@ -3,6 +3,9 @@ require "cases/helper"
class PostgresqlArray < ActiveRecord::Base
end
+class PostgresqlRange < ActiveRecord::Base
+end
+
class PostgresqlTsvector < ActiveRecord::Base
end
@@ -43,7 +46,106 @@ class PostgresqlDataTypeTest < ActiveRecord::TestCase
@connection.execute("INSERT INTO postgresql_arrays (id, commission_by_quarter, nicknames) VALUES (1, '{35000,21000,18000,17000}', '{foo,bar,baz}')")
@first_array = PostgresqlArray.find(1)
+ @connection.execute <<_SQL if @connection.supports_ranges?
+ INSERT INTO postgresql_ranges (
+ date_range,
+ num_range,
+ ts_range,
+ tstz_range,
+ int4_range,
+ int8_range
+ ) VALUES (
+ '[''2012-01-02'', ''2012-01-04'']',
+ '[0.1, 0.2]',
+ '[''2010-01-01 14:30'', ''2011-01-01 14:30'']',
+ '[''2010-01-01 14:30:00+05'', ''2011-01-01 14:30:00-03'']',
+ '[1, 10]',
+ '[10, 100]'
+ )
+_SQL
+
+ @connection.execute <<_SQL if @connection.supports_ranges?
+ INSERT INTO postgresql_ranges (
+ date_range,
+ num_range,
+ ts_range,
+ tstz_range,
+ int4_range,
+ int8_range
+ ) VALUES (
+ '(''2012-01-02'', ''2012-01-04'')',
+ '[0.1, 0.2)',
+ '[''2010-01-01 14:30'', ''2011-01-01 14:30'')',
+ '[''2010-01-01 14:30:00+05'', ''2011-01-01 14:30:00-03'')',
+ '(1, 10)',
+ '(10, 100)'
+ )
+_SQL
+
+ @connection.execute <<_SQL if @connection.supports_ranges?
+ INSERT INTO postgresql_ranges (
+ date_range,
+ num_range,
+ ts_range,
+ tstz_range,
+ int4_range,
+ int8_range
+ ) VALUES (
+ '(''2012-01-02'',]',
+ '[0.1,]',
+ '[''2010-01-01 14:30'',]',
+ '[''2010-01-01 14:30:00+05'',]',
+ '(1,]',
+ '(10,]'
+ )
+_SQL
+
+ @connection.execute <<_SQL if @connection.supports_ranges?
+ INSERT INTO postgresql_ranges (
+ date_range,
+ num_range,
+ ts_range,
+ tstz_range,
+ int4_range,
+ int8_range
+ ) VALUES (
+ '[,]',
+ '[,]',
+ '[,]',
+ '[,]',
+ '[,]',
+ '[,]'
+ )
+_SQL
+
+ @connection.execute <<_SQL if @connection.supports_ranges?
+ INSERT INTO postgresql_ranges (
+ date_range,
+ num_range,
+ ts_range,
+ tstz_range,
+ int4_range,
+ int8_range
+ ) VALUES (
+ '(''2012-01-02'', ''2012-01-02'')',
+ '(0.1, 0.1)',
+ '(''2010-01-01 14:30'', ''2010-01-01 14:30'')',
+ '(''2010-01-01 14:30:00+05'', ''2010-01-01 06:30:00-03'')',
+ '(1, 1)',
+ '(10, 10)'
+ )
+_SQL
+
+ if @connection.supports_ranges?
+ @first_range = PostgresqlRange.find(1)
+ @second_range = PostgresqlRange.find(2)
+ @third_range = PostgresqlRange.find(3)
+ @fourth_range = PostgresqlRange.find(4)
+ @empty_range = PostgresqlRange.find(5)
+ end
+
@connection.execute("INSERT INTO postgresql_tsvectors (id, text_vector) VALUES (1, ' ''text'' ''vector'' ')")
+
@first_tsvector = PostgresqlTsvector.find(1)
@connection.execute("INSERT INTO postgresql_moneys (id, wealth) VALUES (1, '567.89'::money)")
@@ -82,6 +184,16 @@ class PostgresqlDataTypeTest < ActiveRecord::TestCase
assert_equal :text, @first_array.column_for_attribute(:nicknames).type
end
+ def test_data_type_of_range_types
+ skip "PostgreSQL 9.2 required for range datatypes" unless @connection.supports_ranges?
+ assert_equal :daterange, @first_range.column_for_attribute(:date_range).type
+ assert_equal :numrange, @first_range.column_for_attribute(:num_range).type
+ assert_equal :tsrange, @first_range.column_for_attribute(:ts_range).type
+ assert_equal :tstzrange, @first_range.column_for_attribute(:tstz_range).type
+ assert_equal :int4range, @first_range.column_for_attribute(:int4_range).type
+ assert_equal :int8range, @first_range.column_for_attribute(:int8_range).type
+ end
+
def test_data_type_of_tsvector_types
assert_equal :tsvector, @first_tsvector.column_for_attribute(:text_vector).type
end
@@ -128,11 +240,201 @@ class PostgresqlDataTypeTest < ActiveRecord::TestCase
assert_equal "'text' 'vector'", @first_tsvector.text_vector
end
+ def test_int4range_values
+ skip "PostgreSQL 9.2 required for range datatypes" unless @connection.supports_ranges?
+ assert_equal 1...11, @first_range.int4_range
+ assert_equal 2...10, @second_range.int4_range
+ assert_equal 2...Float::INFINITY, @third_range.int4_range
+ assert_equal(-Float::INFINITY...Float::INFINITY, @fourth_range.int4_range)
+ assert_equal nil, @empty_range.int4_range
+ end
+
+ def test_int8range_values
+ skip "PostgreSQL 9.2 required for range datatypes" unless @connection.supports_ranges?
+ assert_equal 10...101, @first_range.int8_range
+ assert_equal 11...100, @second_range.int8_range
+ assert_equal 11...Float::INFINITY, @third_range.int8_range
+ assert_equal(-Float::INFINITY...Float::INFINITY, @fourth_range.int8_range)
+ assert_equal nil, @empty_range.int8_range
+ end
+
+ def test_daterange_values
+ skip "PostgreSQL 9.2 required for range datatypes" unless @connection.supports_ranges?
+ assert_equal Date.new(2012, 1, 2)...Date.new(2012, 1, 5), @first_range.date_range
+ assert_equal Date.new(2012, 1, 3)...Date.new(2012, 1, 4), @second_range.date_range
+ assert_equal Date.new(2012, 1, 3)...Float::INFINITY, @third_range.date_range
+ assert_equal(-Float::INFINITY...Float::INFINITY, @fourth_range.date_range)
+ assert_equal nil, @empty_range.date_range
+ end
+
+ def test_numrange_values
+ skip "PostgreSQL 9.2 required for range datatypes" unless @connection.supports_ranges?
+ assert_equal BigDecimal.new('0.1')..BigDecimal.new('0.2'), @first_range.num_range
+ assert_equal BigDecimal.new('0.1')...BigDecimal.new('0.2'), @second_range.num_range
+ assert_equal BigDecimal.new('0.1')...BigDecimal.new('Infinity'), @third_range.num_range
+ assert_equal BigDecimal.new('-Infinity')...BigDecimal.new('Infinity'), @fourth_range.num_range
+ assert_equal nil, @empty_range.num_range
+ end
+
+ def test_tsrange_values
+ skip "PostgreSQL 9.2 required for range datatypes" unless @connection.supports_ranges?
+ tz = ::ActiveRecord::Base.default_timezone
+ assert_equal Time.send(tz, 2010, 1, 1, 14, 30, 0)..Time.send(tz, 2011, 1, 1, 14, 30, 0), @first_range.ts_range
+ assert_equal Time.send(tz, 2010, 1, 1, 14, 30, 0)...Time.send(tz, 2011, 1, 1, 14, 30, 0), @second_range.ts_range
+ assert_equal Time.send(tz, 2010, 1, 1, 14, 30, 0)...Float::INFINITY, @third_range.ts_range
+ assert_equal(-Float::INFINITY...Float::INFINITY, @fourth_range.ts_range)
+ assert_equal nil, @empty_range.ts_range
+ end
+
+ def test_tstzrange_values
+ skip "PostgreSQL 9.2 required for range datatypes" unless @connection.supports_ranges?
+ assert_equal Time.parse('2010-01-01 09:30:00 UTC')..Time.parse('2011-01-01 17:30:00 UTC'), @first_range.tstz_range
+ assert_equal Time.parse('2010-01-01 09:30:00 UTC')...Time.parse('2011-01-01 17:30:00 UTC'), @second_range.tstz_range
+ assert_equal Time.parse('2010-01-01 09:30:00 UTC')...Float::INFINITY, @third_range.tstz_range
+ assert_equal(-Float::INFINITY...Float::INFINITY, @fourth_range.tstz_range)
+ assert_equal nil, @empty_range.tstz_range
+ end
+
def test_money_values
assert_equal 567.89, @first_money.wealth
assert_equal(-567.89, @second_money.wealth)
end
+ def test_create_tstzrange
+ skip "PostgreSQL 9.2 required for range datatypes" unless @connection.supports_ranges?
+ tstzrange = Time.parse('2010-01-01 14:30:00 +0100')...Time.parse('2011-02-02 14:30:00 CDT')
+ range = PostgresqlRange.new(:tstz_range => tstzrange)
+ assert range.save
+ assert range.reload
+ assert_equal range.tstz_range, tstzrange
+ assert_equal range.tstz_range, Time.parse('2010-01-01 13:30:00 UTC')...Time.parse('2011-02-02 19:30:00 UTC')
+ end
+
+ def test_update_tstzrange
+ skip "PostgreSQL 9.2 required for range datatypes" unless @connection.supports_ranges?
+ new_tstzrange = Time.parse('2010-01-01 14:30:00 CDT')...Time.parse('2011-02-02 14:30:00 CET')
+ assert @first_range.tstz_range = new_tstzrange
+ assert @first_range.save
+ assert @first_range.reload
+ assert_equal @first_range.tstz_range, new_tstzrange
+ assert @first_range.tstz_range = Time.parse('2010-01-01 14:30:00 +0100')...Time.parse('2010-01-01 13:30:00 +0000')
+ assert @first_range.save
+ assert @first_range.reload
+ assert_equal @first_range.tstz_range, nil
+ end
+
+ def test_create_tsrange
+ skip "PostgreSQL 9.2 required for range datatypes" unless @connection.supports_ranges?
+ tz = ::ActiveRecord::Base.default_timezone
+ tsrange = Time.send(tz, 2010, 1, 1, 14, 30, 0)...Time.send(tz, 2011, 2, 2, 14, 30, 0)
+ range = PostgresqlRange.new(:ts_range => tsrange)
+ assert range.save
+ assert range.reload
+ assert_equal range.ts_range, tsrange
+ end
+
+ def test_update_tsrange
+ skip "PostgreSQL 9.2 required for range datatypes" unless @connection.supports_ranges?
+ tz = ::ActiveRecord::Base.default_timezone
+ new_tsrange = Time.send(tz, 2010, 1, 1, 14, 30, 0)...Time.send(tz, 2011, 2, 2, 14, 30, 0)
+ assert @first_range.ts_range = new_tsrange
+ assert @first_range.save
+ assert @first_range.reload
+ assert_equal @first_range.ts_range, new_tsrange
+ assert @first_range.ts_range = Time.send(tz, 2010, 1, 1, 14, 30, 0)...Time.send(tz, 2010, 1, 1, 14, 30, 0)
+ assert @first_range.save
+ assert @first_range.reload
+ assert_equal @first_range.ts_range, nil
+ end
+
+ def test_create_numrange
+ skip "PostgreSQL 9.2 required for range datatypes" unless @connection.supports_ranges?
+ numrange = BigDecimal.new('0.5')...BigDecimal.new('1')
+ range = PostgresqlRange.new(:num_range => numrange)
+ assert range.save
+ assert range.reload
+ assert_equal range.num_range, numrange
+ end
+
+ def test_update_numrange
+ skip "PostgreSQL 9.2 required for range datatypes" unless @connection.supports_ranges?
+ new_numrange = BigDecimal.new('0.5')...BigDecimal.new('1')
+ assert @first_range.num_range = new_numrange
+ assert @first_range.save
+ assert @first_range.reload
+ assert_equal @first_range.num_range, new_numrange
+ assert @first_range.num_range = BigDecimal.new('0.5')...BigDecimal.new('0.5')
+ assert @first_range.save
+ assert @first_range.reload
+ assert_equal @first_range.num_range, nil
+ end
+
+ def test_create_daterange
+ skip "PostgreSQL 9.2 required for range datatypes" unless @connection.supports_ranges?
+ daterange = Range.new(Date.new(2012, 1, 1), Date.new(2013, 1, 1), true)
+ range = PostgresqlRange.new(:date_range => daterange)
+ assert range.save
+ assert range.reload
+ assert_equal range.date_range, daterange
+ end
+
+ def test_update_daterange
+ skip "PostgreSQL 9.2 required for range datatypes" unless @connection.supports_ranges?
+ new_daterange = Date.new(2012, 2, 3)...Date.new(2012, 2, 10)
+ assert @first_range.date_range = new_daterange
+ assert @first_range.save
+ assert @first_range.reload
+ assert_equal @first_range.date_range, new_daterange
+ assert @first_range.date_range = Date.new(2012, 2, 3)...Date.new(2012, 2, 3)
+ assert @first_range.save
+ assert @first_range.reload
+ assert_equal @first_range.date_range, nil
+ end
+
+ def test_create_int4range
+ skip "PostgreSQL 9.2 required for range datatypes" unless @connection.supports_ranges?
+ int4range = Range.new(3, 50, true)
+ range = PostgresqlRange.new(:int4_range => int4range)
+ assert range.save
+ assert range.reload
+ assert_equal range.int4_range, int4range
+ end
+
+ def test_update_int4range
+ skip "PostgreSQL 9.2 required for range datatypes" unless @connection.supports_ranges?
+ new_int4range = 6...10
+ assert @first_range.int4_range = new_int4range
+ assert @first_range.save
+ assert @first_range.reload
+ assert_equal @first_range.int4_range, new_int4range
+ assert @first_range.int4_range = 3...3
+ assert @first_range.save
+ assert @first_range.reload
+ assert_equal @first_range.int4_range, nil
+ end
+
+ def test_create_int8range
+ skip "PostgreSQL 9.2 required for range datatypes" unless @connection.supports_ranges?
+ int8range = Range.new(30, 50, true)
+ range = PostgresqlRange.new(:int8_range => int8range)
+ assert range.save
+ assert range.reload
+ assert_equal range.int8_range, int8range
+ end
+
+ def test_update_int8range
+ skip "PostgreSQL 9.2 required for range datatypes" unless @connection.supports_ranges?
+ new_int8range = 60000...10000000
+ assert @first_range.int8_range = new_int8range
+ assert @first_range.save
+ assert @first_range.reload
+ assert_equal @first_range.int8_range, new_int8range
+ assert @first_range.int8_range = 39999...39999
+ assert @first_range.save
+ assert @first_range.reload
+ assert_equal @first_range.int8_range, nil
+ end
+
def test_update_tsvector
new_text_vector = "'new' 'text' 'vector'"
assert @first_tsvector.text_vector = new_text_vector
diff --git a/activerecord/test/cases/adapters/postgresql/intrange_test.rb b/activerecord/test/cases/adapters/postgresql/intrange_test.rb
deleted file mode 100644
index 5f6a64619d..0000000000
--- a/activerecord/test/cases/adapters/postgresql/intrange_test.rb
+++ /dev/null
@@ -1,106 +0,0 @@
-# encoding: utf-8
-
-require "cases/helper"
-require 'active_record/base'
-require 'active_record/connection_adapters/postgresql_adapter'
-
-class PostgresqlIntrangesTest < ActiveRecord::TestCase
- class IntRangeDataType < ActiveRecord::Base
- self.table_name = 'intrange_data_type'
- end
-
- def setup
- @connection = ActiveRecord::Base.connection
- begin
- @connection.transaction do
- @connection.create_table('intrange_data_type') do |t|
- t.intrange 'int_range', :default => (1..10)
- t.intrange 'long_int_range', :limit => 8, :default => (1..100)
- end
- end
- rescue ActiveRecord::StatementInvalid
- return skip "do not test on PG without ranges"
- end
- @int_range_column = IntRangeDataType.columns.find { |c| c.name == 'int_range' }
- @long_int_range_column = IntRangeDataType.columns.find { |c| c.name == 'long_int_range' }
- end
-
- def teardown
- @connection.execute 'drop table if exists intrange_data_type'
- end
-
- def test_columns
- assert_equal :intrange, @int_range_column.type
- assert_equal :intrange, @long_int_range_column.type
- end
-
- def test_type_cast_intrange
- assert @int_range_column
- assert_equal(true, @int_range_column.has_default?)
- assert_equal((1..10), @int_range_column.default)
- assert_equal("int4range", @int_range_column.sql_type)
-
- data = "[1,10)"
- hash = @int_range_column.class.string_to_intrange data
- assert_equal((1..9), hash)
- assert_equal((1..9), @int_range_column.type_cast(data))
-
- assert_equal((nil..nil), @int_range_column.type_cast("empty"))
- assert_equal((1..5), @int_range_column.type_cast('[1,5]'))
- assert_equal((2..4), @int_range_column.type_cast('(1,5)'))
- assert_equal((2..39), @int_range_column.type_cast('[2,40)'))
- assert_equal((10..20), @int_range_column.type_cast('(9,20]'))
- end
-
- def test_type_cast_long_intrange
- assert @long_int_range_column
- assert_equal(true, @long_int_range_column.has_default?)
- assert_equal((1..100), @long_int_range_column.default)
- assert_equal("int8range", @long_int_range_column.sql_type)
- end
-
- def test_rewrite
- @connection.execute "insert into intrange_data_type (int_range) VALUES ('(1, 6)')"
- x = IntRangeDataType.first
- x.int_range = (1..100)
- assert x.save!
- end
-
- def test_select
- @connection.execute "insert into intrange_data_type (int_range) VALUES ('(1, 4]')"
- x = IntRangeDataType.first
- assert_equal((2..4), x.int_range)
- end
-
- def test_empty_range
- @connection.execute %q|insert into intrange_data_type (int_range) VALUES('empty')|
- x = IntRangeDataType.first
- assert_equal((nil..nil), x.int_range)
- end
-
- def test_rewrite_to_nil
- @connection.execute %q|insert into intrange_data_type (int_range) VALUES('(1, 4]')|
- x = IntRangeDataType.first
- x.int_range = nil
- assert x.save!
- assert_equal(nil, x.int_range)
- end
-
- def test_invalid_intrange
- assert IntRangeDataType.create!(int_range: ('a'..'d'))
- x = IntRangeDataType.first
- assert_equal(nil, x.int_range)
- end
-
- def test_save_empty_range
- assert IntRangeDataType.create!(int_range: (nil..nil))
- x = IntRangeDataType.first
- assert_equal((nil..nil), x.int_range)
- end
-
- def test_save_invalid_data
- assert_raises(ActiveRecord::StatementInvalid) do
- IntRangeDataType.create!(int_range: "empty1")
- end
- end
-end
diff --git a/activerecord/test/cases/associations/habtm_join_table_test.rb b/activerecord/test/cases/associations/habtm_join_table_test.rb
deleted file mode 100644
index 44aaa65416..0000000000
--- a/activerecord/test/cases/associations/habtm_join_table_test.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-require 'cases/helper'
-
-class MyReader < ActiveRecord::Base
- has_and_belongs_to_many :my_books
-end
-
-class MyBook < ActiveRecord::Base
- has_and_belongs_to_many :my_readers
-end
-
-class HabtmJoinTableTest < ActiveRecord::TestCase
- def test_habtm_join_table
- ActiveRecord::Base.connection.create_table :my_books, :force => true do |t|
- t.string :name
- end
- assert ActiveRecord::Base.connection.table_exists?(:my_books)
-
- ActiveRecord::Base.connection.create_table :my_readers, :force => true do |t|
- t.string :name
- end
- assert ActiveRecord::Base.connection.table_exists?(:my_readers)
-
- ActiveRecord::Base.connection.create_table :my_books_my_readers, :force => true do |t|
- t.integer :my_book_id
- t.integer :my_reader_id
- end
- assert ActiveRecord::Base.connection.table_exists?(:my_books_my_readers)
- end
-
- def teardown
- ActiveRecord::Base.connection.drop_table :my_books
- ActiveRecord::Base.connection.drop_table :my_readers
- ActiveRecord::Base.connection.drop_table :my_books_my_readers
- end
-end
diff --git a/activerecord/test/cases/helper.rb b/activerecord/test/cases/helper.rb
index 5ffb32e809..7dbb6616f8 100644
--- a/activerecord/test/cases/helper.rb
+++ b/activerecord/test/cases/helper.rb
@@ -15,6 +15,8 @@ require 'support/connection'
# TODO: Move all these random hacks into the ARTest namespace and into the support/ dir
+Thread.abort_on_exception = true
+
# Show backtraces for deprecated behavior for quicker cleanup.
ActiveSupport::Deprecation.debug = true
diff --git a/activerecord/test/cases/relation/where_test.rb b/activerecord/test/cases/relation/where_test.rb
index f69a248491..c43c7601a2 100644
--- a/activerecord/test/cases/relation/where_test.rb
+++ b/activerecord/test/cases/relation/where_test.rb
@@ -8,7 +8,20 @@ require 'models/edge'
module ActiveRecord
class WhereTest < ActiveRecord::TestCase
- fixtures :posts, :edges
+ fixtures :posts, :edges, :authors
+
+ def test_where_copies_bind_params
+ author = authors(:david)
+ posts = author.posts.where('posts.id != 1')
+ joined = Post.where(id: posts)
+
+ assert_operator joined.length, :>, 0
+
+ joined.each { |post|
+ assert_equal author, post.author
+ assert_not_equal 1, post.id
+ }
+ end
def test_belongs_to_shallow_where
author = Author.new
diff --git a/activerecord/test/models/author.rb b/activerecord/test/models/author.rb
index 6935cfb0ea..83904cd850 100644
--- a/activerecord/test/models/author.rb
+++ b/activerecord/test/models/author.rb
@@ -9,17 +9,7 @@ class Author < ActiveRecord::Base
has_many :posts_with_categories, -> { includes(:categories) }, :class_name => "Post"
has_many :posts_with_comments_and_categories, -> { includes(:comments, :categories).order("posts.id") }, :class_name => "Post"
has_many :posts_containing_the_letter_a, :class_name => "Post"
- has_many :posts_with_extension, :class_name => "Post" do #, :extend => ProxyTestExtension
- def testing_proxy_owner
- proxy_owner
- end
- def testing_proxy_reflection
- proxy_reflection
- end
- def testing_proxy_target
- proxy_target
- end
- end
+ has_many :posts_with_extension, :class_name => "Post"
has_one :post_about_thinking, -> { where("posts.title like '%thinking%'") }, :class_name => 'Post'
has_one :post_about_thinking_with_last_comment, -> { where("posts.title like '%thinking%'").includes(:last_comment) }, :class_name => 'Post'
has_many :comments, :through => :posts
diff --git a/activerecord/test/models/category.rb b/activerecord/test/models/category.rb
index f8c8ebb70c..7da39a8e33 100644
--- a/activerecord/test/models/category.rb
+++ b/activerecord/test/models/category.rb
@@ -31,9 +31,4 @@ class Category < ActiveRecord::Base
end
class SpecialCategory < Category
-
- def self.what_are_you
- 'a special category...'
- end
-
end
diff --git a/activerecord/test/models/comment.rb b/activerecord/test/models/comment.rb
index 4b2015fe01..ede5fbd0c6 100644
--- a/activerecord/test/models/comment.rb
+++ b/activerecord/test/models/comment.rb
@@ -29,16 +29,10 @@ class Comment < ActiveRecord::Base
end
class SpecialComment < Comment
- def self.what_are_you
- 'a special comment...'
- end
end
class SubSpecialComment < SpecialComment
end
class VerySpecialComment < Comment
- def self.what_are_you
- 'a very special comment...'
- end
end
diff --git a/activerecord/test/models/post.rb b/activerecord/test/models/post.rb
index 603f1f2555..73ffc0de38 100644
--- a/activerecord/test/models/post.rb
+++ b/activerecord/test/models/post.rb
@@ -16,11 +16,7 @@ class Post < ActiveRecord::Base
scope :limit_by, lambda {|l| limit(l) }
- belongs_to :author do
- def greeting
- "hello"
- end
- end
+ belongs_to :author
belongs_to :author_with_posts, -> { includes(:posts) }, :class_name => "Author", :foreign_key => :author_id
belongs_to :author_with_address, -> { includes(:author_address) }, :class_name => "Author", :foreign_key => :author_id
@@ -168,18 +164,6 @@ class SubStiPost < StiPost
self.table_name = Post.table_name
end
-ActiveSupport::Deprecation.silence do
- class DeprecatedPostWithComment < ActiveRecord::Base
- self.table_name = 'posts'
- default_scope where("posts.comments_count > 0").order("posts.comments_count ASC")
- end
-end
-
-class PostForAuthor < ActiveRecord::Base
- self.table_name = 'posts'
- cattr_accessor :selected_author
-end
-
class FirstPost < ActiveRecord::Base
self.table_name = 'posts'
default_scope { where(:id => 1) }
diff --git a/activerecord/test/models/project.rb b/activerecord/test/models/project.rb
index af3ec4be83..90273adafc 100644
--- a/activerecord/test/models/project.rb
+++ b/activerecord/test/models/project.rb
@@ -40,7 +40,4 @@ class Project < ActiveRecord::Base
end
class SpecialProject < Project
- def hello_world
- "hello there!"
- end
end
diff --git a/activerecord/test/models/topic.rb b/activerecord/test/models/topic.rb
index f7f4cebc5a..17035bf338 100644
--- a/activerecord/test/models/topic.rb
+++ b/activerecord/test/models/topic.rb
@@ -108,6 +108,7 @@ class ImportantTopic < Topic
end
class BlankTopic < Topic
+ # declared here to make sure that dynamic finder with a bang can find a model that responds to `blank?`
def blank?
true
end
diff --git a/activerecord/test/schema/postgresql_specific_schema.rb b/activerecord/test/schema/postgresql_specific_schema.rb
index ae13f2cd8a..83b50030bd 100644
--- a/activerecord/test/schema/postgresql_specific_schema.rb
+++ b/activerecord/test/schema/postgresql_specific_schema.rb
@@ -1,7 +1,7 @@
ActiveRecord::Schema.define do
- %w(postgresql_tsvectors postgresql_hstores postgresql_arrays postgresql_moneys postgresql_numbers postgresql_times postgresql_network_addresses postgresql_bit_strings postgresql_uuids postgresql_ltrees
- postgresql_oids postgresql_xml_data_type defaults geometrics postgresql_timestamp_with_zones postgresql_partitioned_table postgresql_partitioned_table_parent postgresql_json_data_type postgresql_intrange_data_type).each do |table_name|
+ %w(postgresql_ranges postgresql_tsvectors postgresql_hstores postgresql_arrays postgresql_moneys postgresql_numbers postgresql_times postgresql_network_addresses postgresql_bit_strings postgresql_uuids postgresql_ltrees
+ postgresql_oids postgresql_xml_data_type defaults geometrics postgresql_timestamp_with_zones postgresql_partitioned_table postgresql_partitioned_table_parent postgresql_json_data_type).each do |table_name|
execute "DROP TABLE IF EXISTS #{quote_table_name table_name}"
end
@@ -73,6 +73,18 @@ _SQL
);
_SQL
+ execute <<_SQL if supports_ranges?
+ CREATE TABLE postgresql_ranges (
+ id SERIAL PRIMARY KEY,
+ date_range daterange,
+ num_range numrange,
+ ts_range tsrange,
+ tstz_range tstzrange,
+ int4_range int4range,
+ int8_range int8range
+ );
+_SQL
+
execute <<_SQL
CREATE TABLE postgresql_tsvectors (
id SERIAL PRIMARY KEY,
@@ -106,16 +118,6 @@ _SQL
);
_SQL
end
-
- if 't' == select_value("select 'int4range'=ANY(select typname from pg_type)")
- execute <<_SQL
- CREATE TABLE postgresql_intrange_data_type (
- id SERIAL PRIMARY KEY,
- int_range int4range,
- int_long_range int8range
- );
-_SQL
- end
execute <<_SQL
CREATE TABLE postgresql_moneys (
diff --git a/activesupport/test/abstract_unit.rb b/activesupport/test/abstract_unit.rb
index 90e50f235b..dd17cb64f4 100644
--- a/activesupport/test/abstract_unit.rb
+++ b/activesupport/test/abstract_unit.rb
@@ -21,5 +21,7 @@ require 'empty_bool'
ENV['NO_RELOAD'] = '1'
require 'active_support'
+Thread.abort_on_exception = true
+
# Show backtraces for deprecated behavior for quicker cleanup.
ActiveSupport::Deprecation.debug = true
diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md
index 3b0f282143..c6ffe30ad3 100644
--- a/railties/CHANGELOG.md
+++ b/railties/CHANGELOG.md
@@ -1,5 +1,19 @@
## Rails 4.0.0 (unreleased) ##
+* Fixes database.yml when creating a new rails application with '.'
+ Fix #8304
+
+ *Jeremy W. Rowe*
+
+* Deprecate the `eager_load_paths` configuration and alias it to `autoload_paths`.
+ Since the default in Rails 4.0 is to run in 'threadsafe' mode we need to eager
+ load all of the paths in `autoload_paths`. This may have unintended consequences
+ if you have added 'lib' to `autoload_paths` such as loading unneeded code or
+ code intended only for development and/or test environments. If this applies to
+ your application you should thoroughly check what is being eager loaded.
+
+ *Andrew White*
+
* Restore Rails::Engine::Railties#engines with deprecation to ensure
compatibility with gems such as Thinking Sphinx
Fix #8551
diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb
index 46a6485c44..8a6d1f34aa 100644
--- a/railties/lib/rails/engine.rb
+++ b/railties/lib/rails/engine.rb
@@ -34,9 +34,8 @@ module Rails
# == Configuration
#
# Besides the +Railtie+ configuration which is shared across the application, in a
- # <tt>Rails::Engine</tt> you can access <tt>autoload_paths</tt>, <tt>eager_load_paths</tt>
- # and <tt>autoload_once_paths</tt>, which, differently from a <tt>Railtie</tt>, are scoped to
- # the current engine.
+ # <tt>Rails::Engine</tt> you can access <tt>autoload_paths</tt> and <tt>autoload_once_paths</tt>,
+ # which, differently from a <tt>Railtie</tt>, are scoped to the current engine.
#
# class MyEngine < Rails::Engine
# # Add a load path for this specific Engine
@@ -456,9 +455,9 @@ module Rails
end
# Eager load the application by loading all ruby
- # files inside eager_load paths.
+ # files inside autoload_paths.
def eager_load!
- config.eager_load_paths.each do |load_path|
+ config.autoload_paths.each do |load_path|
matcher = /\A#{Regexp.escape(load_path)}\/(.*)\.rb\Z/
Dir.glob("#{load_path}/**/*.rb").sort.each do |file|
require_dependency file.sub(matcher, '\1')
@@ -558,7 +557,6 @@ module Rails
# Freeze so future modifications will fail rather than do nothing mysteriously
config.autoload_paths.freeze
- config.eager_load_paths.freeze
config.autoload_once_paths.freeze
end
@@ -671,7 +669,7 @@ module Rails
end
def _all_autoload_paths #:nodoc:
- @_all_autoload_paths ||= (config.autoload_paths + config.eager_load_paths + config.autoload_once_paths).uniq
+ @_all_autoload_paths ||= (config.autoload_paths + config.autoload_once_paths).uniq
end
def _all_load_paths #:nodoc:
diff --git a/railties/lib/rails/engine/configuration.rb b/railties/lib/rails/engine/configuration.rb
index 10d1821709..2b23d8be38 100644
--- a/railties/lib/rails/engine/configuration.rb
+++ b/railties/lib/rails/engine/configuration.rb
@@ -4,7 +4,7 @@ module Rails
class Engine
class Configuration < ::Rails::Railtie::Configuration
attr_reader :root
- attr_writer :middleware, :eager_load_paths, :autoload_once_paths, :autoload_paths
+ attr_writer :middleware, :autoload_once_paths, :autoload_paths
def initialize(root=nil)
super()
@@ -39,16 +39,16 @@ module Rails
@paths ||= begin
paths = Rails::Paths::Root.new(@root)
- paths.add "app", eager_load: true, glob: "*"
+ paths.add "app", autoload: true, glob: "*"
paths.add "app/assets", glob: "*"
- paths.add "app/controllers", eager_load: true
- paths.add "app/helpers", eager_load: true
- paths.add "app/models", eager_load: true
- paths.add "app/mailers", eager_load: true
+ paths.add "app/controllers", autoload: true
+ paths.add "app/helpers", autoload: true
+ paths.add "app/models", autoload: true
+ paths.add "app/mailers", autoload: true
paths.add "app/views"
- paths.add "app/controllers/concerns", eager_load: true
- paths.add "app/models/concerns", eager_load: true
+ paths.add "app/controllers/concerns", autoload: true
+ paths.add "app/models/concerns", autoload: true
paths.add "lib", load_path: true
paths.add "lib/assets", glob: "*"
@@ -76,7 +76,13 @@ module Rails
end
def eager_load_paths
- @eager_load_paths ||= paths.eager_load
+ ActiveSupport::Deprecation.warn "eager_load_paths is deprecated and all autoload_paths are now eagerly loaded."
+ autoload_paths
+ end
+
+ def eager_load_paths=(paths)
+ ActiveSupport::Deprecation.warn "eager_load_paths is deprecated and all autoload_paths are now eagerly loaded."
+ self.autoload_paths = paths
end
def autoload_once_paths
diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb
index e22be40381..b2d1be9b51 100644
--- a/railties/lib/rails/generators/rails/app/app_generator.rb
+++ b/railties/lib/rails/generators/rails/app/app_generator.rb
@@ -236,7 +236,7 @@ module Rails
end
def app_name
- @app_name ||= defined_app_const_base? ? defined_app_name : File.basename(destination_root)
+ @app_name ||= (defined_app_const_base? ? defined_app_name : File.basename(destination_root)).tr(".", "_")
end
def defined_app_name
diff --git a/railties/lib/rails/paths.rb b/railties/lib/rails/paths.rb
index de6795eda2..80ba144441 100644
--- a/railties/lib/rails/paths.rb
+++ b/railties/lib/rails/paths.rb
@@ -5,13 +5,13 @@ module Rails
# paths by a Hash like API. It requires you to give a physical path on initialization.
#
# root = Root.new "/rails"
- # root.add "app/controllers", eager_load: true
+ # root.add "app/controllers", autoload: true
#
# The command above creates a new root object and add "app/controllers" as a path.
# This means we can get a <tt>Rails::Paths::Path</tt> object back like below:
#
# path = root["app/controllers"]
- # path.eager_load? # => true
+ # path.autoload? # => true
# path.is_a?(Rails::Paths::Path) # => true
#
# The +Path+ object is simply an enumerable and allows you to easily add extra paths:
@@ -30,7 +30,7 @@ module Rails
# root["config/routes"].inspect # => ["config/routes.rb"]
#
# The +add+ method accepts the following options as arguments:
- # eager_load, autoload, autoload_once and glob.
+ # autoload, autoload_once and glob.
#
# Finally, the +Path+ object also provides a few helpers:
#
@@ -85,7 +85,8 @@ module Rails
end
def eager_load
- filter_by(:eager_load?)
+ ActiveSupport::Deprecation.warn "eager_load is deprecated and all autoload_paths are now eagerly loaded."
+ filter_by(:autoload?)
end
def autoload_paths
@@ -124,9 +125,13 @@ module Rails
@glob = options[:glob]
options[:autoload_once] ? autoload_once! : skip_autoload_once!
- options[:eager_load] ? eager_load! : skip_eager_load!
options[:autoload] ? autoload! : skip_autoload!
options[:load_path] ? load_path! : skip_load_path!
+
+ if !options.key?(:autoload) && options.key?(:eager_load)
+ ActiveSupport::Deprecation.warn "the :eager_load option is deprecated and all :autoload paths are now eagerly loaded."
+ options[:eager_load] ? autoload! : skip_autoload!
+ end
end
def children
@@ -143,22 +148,37 @@ module Rails
expanded.last
end
- %w(autoload_once eager_load autoload load_path).each do |m|
+ %w(autoload_once autoload load_path).each do |m|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
- def #{m}! # def eager_load!
- @#{m} = true # @eager_load = true
+ def #{m}! # def autoload!
+ @#{m} = true # @autoload = true
end # end
#
- def skip_#{m}! # def skip_eager_load!
- @#{m} = false # @eager_load = false
+ def skip_#{m}! # def skip_autoload!
+ @#{m} = false # @autoload = false
end # end
#
- def #{m}? # def eager_load?
- @#{m} # @eager_load
+ def #{m}? # def autoload?
+ @#{m} # @autoload
end # end
RUBY
end
+ def eager_load!
+ ActiveSupport::Deprecation.warn "eager_load paths are deprecated and all autoload paths are now eagerly loaded."
+ autoload!
+ end
+
+ def skip_eager_load!
+ ActiveSupport::Deprecation.warn "eager_load paths are deprecated and all autoload paths are now eagerly loaded."
+ skip_autoload!
+ end
+
+ def eager_load?
+ ActiveSupport::Deprecation.warn "eager_load paths are deprecated and all autoload paths are now eagerly loaded."
+ autoload?
+ end
+
def each(&block)
@paths.each(&block)
end
diff --git a/railties/railties.gemspec b/railties/railties.gemspec
index e39430560f..a55bf012da 100644
--- a/railties/railties.gemspec
+++ b/railties/railties.gemspec
@@ -27,6 +27,6 @@ Gem::Specification.new do |s|
s.add_dependency 'actionpack', version
s.add_dependency 'rake', '>= 0.8.7'
- s.add_dependency 'thor', '>= 0.15.4', '< 2.0'
+ s.add_dependency 'thor', '>= 0.17.0', '< 2.0'
s.add_dependency 'rdoc', '~> 3.4'
end
diff --git a/railties/test/application/initializers/load_path_test.rb b/railties/test/application/initializers/load_path_test.rb
index 31811e7f92..595f58bd91 100644
--- a/railties/test/application/initializers/load_path_test.rb
+++ b/railties/test/application/initializers/load_path_test.rb
@@ -64,7 +64,7 @@ module ApplicationTests
add_to_config <<-RUBY
config.root = "#{app_path}"
- config.eager_load_paths << "#{app_path}/lib"
+ config.autoload_paths << "#{app_path}/lib"
RUBY
require "#{app_path}/config/environment"
diff --git a/railties/test/application/paths_test.rb b/railties/test/application/paths_test.rb
index 4029984ce9..f6a77a0d17 100644
--- a/railties/test/application/paths_test.rb
+++ b/railties/test/application/paths_test.rb
@@ -54,11 +54,11 @@ module ApplicationTests
assert_equal root("app", "controllers"), @paths["app/controllers"].expanded.first
end
- test "booting up Rails yields a list of paths that are eager" do
- eager_load = @paths.eager_load
- assert eager_load.include?(root("app/controllers"))
- assert eager_load.include?(root("app/helpers"))
- assert eager_load.include?(root("app/models"))
+ test "booting up Rails yields a list of paths that will be eager loaded" do
+ autoload_paths = @paths.autoload_paths
+ assert autoload_paths.include?(root("app/controllers"))
+ assert autoload_paths.include?(root("app/helpers"))
+ assert autoload_paths.include?(root("app/models"))
end
test "environments has a glob equal to the current environment" do
diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb
index ee93dc49cd..b2deeb011d 100644
--- a/railties/test/generators/app_generator_test.rb
+++ b/railties/test/generators/app_generator_test.rb
@@ -164,6 +164,11 @@ class AppGeneratorTest < Rails::Generators::TestCase
end
end
+ def test_config_database_app_name_with_period
+ run_generator [File.join(destination_root, "common.usage.com"), "-d", "postgresql"]
+ assert_file "common.usage.com/config/database.yml", /common_usage_com/
+ end
+
def test_config_postgresql_database
run_generator([destination_root, "-d", "postgresql"])
assert_file "config/database.yml", /postgresql/
diff --git a/railties/test/paths_test.rb b/railties/test/paths_test.rb
index 12f18b9dbf..6f860469fd 100644
--- a/railties/test/paths_test.rb
+++ b/railties/test/paths_test.rb
@@ -135,56 +135,48 @@ class PathsTest < ActiveSupport::TestCase
assert_equal 2, @root.autoload_once.size
end
- test "it is possible to mark a path as eager loaded" do
+ test "marking a path as eager loaded is deprecated" do
@root["app"] = "/app"
- @root["app"].eager_load!
- assert @root["app"].eager_load?
- assert @root.eager_load.include?(@root["app"].to_a.first)
+ assert_deprecated{ @root["app"].eager_load! }
+ assert_deprecated{ assert @root["app"].eager_load? }
+ assert_deprecated{ assert @root.eager_load.include?(@root["app"].to_a.first) }
end
- test "it is possible to skip a path from eager loading" do
+ test "skipping a path from eager loading is deprecated" do
@root["app"] = "/app"
- @root["app"].eager_load!
- assert @root["app"].eager_load?
+ assert_deprecated{ @root["app"].eager_load! }
+ assert_deprecated{ assert @root["app"].eager_load? }
- @root["app"].skip_eager_load!
- assert !@root["app"].eager_load?
- assert !@root.eager_load.include?(@root["app"].to_a.first)
+ assert_deprecated{ @root["app"].skip_eager_load! }
+ assert_deprecated{ assert !@root["app"].eager_load? }
+ assert_deprecated{ assert !@root.eager_load.include?(@root["app"].to_a.first) }
end
- test "it is possible to add a path without assignment and mark it as eager" do
- @root.add "app", with: "/app", eager_load: true
- assert @root["app"].eager_load?
- assert @root.eager_load.include?("/app")
+ test "adding a path with eager_load option is deprecated" do
+ assert_deprecated{ @root.add "app", with: "/app", eager_load: true }
+ assert_deprecated{ assert @root["app"].eager_load? }
+ assert_deprecated{ assert @root.eager_load.include?("/app") }
end
- test "it is possible to add multiple paths without assignment and mark them as eager" do
- @root.add "app", with: ["/app", "/app2"], eager_load: true
- assert @root["app"].eager_load?
- assert @root.eager_load.include?("/app")
- assert @root.eager_load.include?("/app2")
- end
-
- test "it is possible to create a path without assignment and mark it both as eager and load once" do
- @root.add "app", with: "/app", eager_load: true, autoload_once: true
- assert @root["app"].eager_load?
- assert @root["app"].autoload_once?
- assert @root.eager_load.include?("/app")
- assert @root.autoload_once.include?("/app")
+ test "adding multiple paths with eager_load option is deprecated" do
+ assert_deprecated{ @root.add "app", with: ["/app", "/app2"], eager_load: true }
+ assert_deprecated{ assert @root["app"].eager_load? }
+ assert_deprecated{ assert @root.eager_load.include?("/app") }
+ assert_deprecated{ assert @root.eager_load.include?("/app2") }
end
test "making a path eager more than once only includes it once in @root.eager_paths" do
@root["app"] = "/app"
- @root["app"].eager_load!
- @root["app"].eager_load!
- assert_equal 1, @root.eager_load.select {|p| p == @root["app"].expanded.first }.size
+ assert_deprecated{ @root["app"].eager_load! }
+ assert_deprecated{ @root["app"].eager_load! }
+ assert_deprecated{ assert_equal 1, @root.eager_load.select {|p| p == @root["app"].expanded.first }.size }
end
test "paths added to a eager_load path should be added to the eager_load collection" do
@root["app"] = "/app"
- @root["app"].eager_load!
+ assert_deprecated{ @root["app"].eager_load! }
@root["app"] << "/app2"
- assert_equal 2, @root.eager_load.size
+ assert_deprecated{ assert_equal 2, @root.eager_load.size }
end
test "it should be possible to add a path's default glob" do