aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.codeclimate.yml14
-rw-r--r--Gemfile3
-rw-r--r--Gemfile.lock15
-rw-r--r--actionpack/CHANGELOG.md7
-rw-r--r--actionpack/lib/action_dispatch/http/parameters.rb2
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb9
-rw-r--r--actionpack/lib/action_dispatch/testing/integration.rb6
-rw-r--r--actionpack/test/dispatch/routing_test.rb18
-rw-r--r--actionview/CHANGELOG.md11
-rw-r--r--actionview/lib/action_view/helpers/asset_tag_helper.rb9
-rw-r--r--actionview/lib/action_view/helpers/asset_url_helper.rb23
-rw-r--r--actionview/lib/action_view/helpers/translation_helper.rb3
-rw-r--r--actionview/lib/action_view/helpers/url_helper.rb3
-rw-r--r--actionview/lib/action_view/layouts.rb7
-rw-r--r--actionview/lib/action_view/renderer/partial_renderer.rb7
-rw-r--r--actionview/lib/action_view/renderer/template_renderer.rb2
-rw-r--r--actionview/lib/action_view/template/error.rb3
-rw-r--r--actionview/lib/action_view/template/handlers/erb.rb5
-rw-r--r--actionview/lib/action_view/testing/resolvers.rb4
-rw-r--r--actionview/test/actionpack/controller/layout_test.rb3
-rw-r--r--actionview/test/template/render_test.rb8
-rw-r--r--activejob/lib/active_job/core.rb1
-rw-r--r--activejob/lib/active_job/queue_adapters/sidekiq_adapter.rb2
-rw-r--r--activejob/test/integration/queuing_test.rb9
-rw-r--r--activejob/test/jobs/provider_jid_job.rb7
-rw-r--r--activemodel/lib/active_model/attribute_methods.rb5
-rw-r--r--activemodel/lib/active_model/type/time.rb2
-rw-r--r--activemodel/lib/active_model/validations/format.rb5
-rw-r--r--activemodel/test/validators/email_validator.rb6
-rw-r--r--activerecord/CHANGELOG.md9
-rw-r--r--activerecord/lib/active_record/associations/collection_proxy.rb6
-rw-r--r--activerecord/lib/active_record/associations/has_one_through_association.rb2
-rw-r--r--activerecord/lib/active_record/associations/join_dependency/join_association.rb4
-rw-r--r--activerecord/lib/active_record/attribute.rb4
-rw-r--r--activerecord/lib/active_record/attribute_set.rb2
-rw-r--r--activerecord/lib/active_record/attribute_set/builder.rb28
-rw-r--r--activerecord/lib/active_record/attributes.rb2
-rw-r--r--activerecord/lib/active_record/coders/yaml_column.rb1
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb9
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/quoting.rb16
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_adapter.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb18
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql/quoting.rb6
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb4
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb4
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb4
-rw-r--r--activerecord/lib/active_record/connection_adapters/sqlite3/quoting.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb6
-rw-r--r--activerecord/lib/active_record/dynamic_matchers.rb2
-rw-r--r--activerecord/lib/active_record/migration.rb3
-rw-r--r--activerecord/lib/active_record/model_schema.rb6
-rw-r--r--activerecord/lib/active_record/relation/delegation.rb1
-rw-r--r--activerecord/lib/active_record/relation/query_methods.rb1
-rw-r--r--activerecord/lib/active_record/sanitization.rb2
-rw-r--r--activerecord/lib/active_record/schema_dumper.rb8
-rw-r--r--activerecord/lib/active_record/statement_cache.rb17
-rw-r--r--activerecord/lib/active_record/table_metadata.rb6
-rw-r--r--activerecord/lib/rails/generators/active_record/migration/migration_generator.rb1
-rw-r--r--activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb6
-rw-r--r--activerecord/test/cases/associations/has_many_associations_test.rb48
-rw-r--r--activerecord/test/cases/associations/left_outer_join_association_test.rb1
-rw-r--r--activerecord/test/cases/associations_test.rb10
-rw-r--r--activerecord/test/cases/attributes_test.rb44
-rw-r--r--activerecord/test/cases/nested_attributes_test.rb8
-rw-r--r--activerecord/test/cases/quoting_test.rb16
-rw-r--r--activerecord/test/cases/scoping/default_scoping_test.rb1
-rw-r--r--activerecord/test/cases/scoping/relation_scoping_test.rb7
-rw-r--r--activerecord/test/cases/test_case.rb1
-rw-r--r--activerecord/test/models/user.rb6
-rw-r--r--activerecord/test/schema/schema.rb5
-rw-r--r--activesupport/lib/active_support/message_encryptor.rb4
-rw-r--r--guides/source/active_record_querying.md1
-rw-r--r--guides/source/getting_started.md33
-rw-r--r--railties/CHANGELOG.md4
-rw-r--r--railties/lib/rails/generators/app_base.rb8
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt4
-rw-r--r--railties/test/application/integration_test_case_test.rb28
-rw-r--r--railties/test/generators/app_generator_test.rb5
79 files changed, 467 insertions, 150 deletions
diff --git a/.codeclimate.yml b/.codeclimate.yml
index 877c67873d..17fcaa4360 100644
--- a/.codeclimate.yml
+++ b/.codeclimate.yml
@@ -7,20 +7,6 @@ ratings:
- "**.rb"
exclude_paths:
- - actioncable/lib/rails/generators/
- - actioncable/test/
- - actionmailer/lib/rails/generators/
- - actionmailer/test/
- - actionpack/test/
- - actionview/test/
- - activejob/lib/rails/generators/
- - activejob/test/
- - activemodel/test/
- - activerecord/lib/rails/generators/
- - activerecord/test/
- - activesupport/test/
- - railties/lib/rails/generators/
- - railties/test/
- ci/
- guides/
- tasks/
diff --git a/Gemfile b/Gemfile
index 8696b85694..7b0b442aa4 100644
--- a/Gemfile
+++ b/Gemfile
@@ -27,6 +27,9 @@ gem 'uglifier', '>= 1.3.0', require: false
# Track stable branch of sass because it doesn't have circular require warnings.
gem 'sass', github: 'sass/sass', branch: 'stable', require: false
+# FIXME: Remove this fork after https://github.com/nex3/rb-inotify/pull/49 is fixed.
+gem 'rb-inotify', github: 'matthewd/rb-inotify', branch: 'close-handling', require: false
+
group :doc do
gem 'sdoc', '~> 0.4.0'
gem 'redcarpet', '~> 3.2.3', platforms: :ruby
diff --git a/Gemfile.lock b/Gemfile.lock
index 9fb842ac2c..cf8bb0fec9 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -22,6 +22,14 @@ GIT
delayed_job (>= 3.0, < 5)
GIT
+ remote: git://github.com/matthewd/rb-inotify.git
+ revision: 90553518d1fb79aedc98a3036c59bd2b6731ac40
+ branch: close-handling
+ specs:
+ rb-inotify (0.9.7)
+ ffi (>= 0.5.0)
+
+GIT
remote: git://github.com/resque/resque.git
revision: 06036388ec61e573c761ac5a25a2ef3c76537ec7
specs:
@@ -103,7 +111,7 @@ GEM
specs:
addressable (2.4.0)
amq-protocol (2.0.1)
- arel (7.0.0)
+ arel (7.1.1)
backburner (1.3.0)
beaneater (~> 1.0)
dante (> 0.1.5)
@@ -254,8 +262,6 @@ GEM
loofah (~> 2.0)
rake (11.1.2)
rb-fsevent (0.9.7)
- rb-inotify (0.9.7)
- ffi (>= 0.5.0)
rdoc (4.2.2)
json (~> 1.4)
redcarpet (3.2.3)
@@ -381,6 +387,7 @@ DEPENDENCIES
rack-cache (~> 1.2)
rails!
rake (>= 11.1)
+ rb-inotify!
redcarpet (~> 3.2.3)
redis
resque!
@@ -401,4 +408,4 @@ DEPENDENCIES
wdm (>= 0.1.0)
BUNDLED WITH
- 1.11.2
+ 1.12.5
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index d50cbaee38..7bb9b62468 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -1,3 +1,10 @@
+* Fix 'defaults' option for root route.
+
+ A regression from some refactoring for the 5.0 release, this change
+ fixes the use of 'defaults' (default parameters) in the 'root' routing method.
+
+ *Chris Arcand*
+
* Check `request.path_parameters` encoding at the point they're set.
Check for any non-UTF8 characters in path parameters at the point they're
diff --git a/actionpack/lib/action_dispatch/http/parameters.rb b/actionpack/lib/action_dispatch/http/parameters.rb
index 3f0e51790c..ea0e2ee41f 100644
--- a/actionpack/lib/action_dispatch/http/parameters.rb
+++ b/actionpack/lib/action_dispatch/http/parameters.rb
@@ -65,7 +65,7 @@ module ActionDispatch
private
def parse_formatted_parameters(parsers)
- return yield if content_length.zero?
+ return yield if content_length.zero? || content_mime_type.nil?
strategy = parsers.fetch(content_mime_type.symbol) { return yield }
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index 73b4864e45..12ddd0f148 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -1923,7 +1923,14 @@ to this:
def match_root_route(options)
name = has_named_route?(:root) ? nil : :root
- match '/', { :as => name, :via => :get }.merge!(options)
+ defaults_option = options.delete(:defaults)
+ args = ['/', { as: name, via: :get }.merge!(options)]
+
+ if defaults_option
+ defaults(defaults_option) { match(*args) }
+ else
+ match(*args)
+ end
end
end
diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb
index 4897f44268..9a76b68ae1 100644
--- a/actionpack/lib/action_dispatch/testing/integration.rb
+++ b/actionpack/lib/action_dispatch/testing/integration.rb
@@ -717,7 +717,11 @@ module ActionDispatch
module ClassMethods
def app
- defined?(@@app) ? @@app : ActionDispatch.test_app
+ if defined?(@@app) && @@app
+ @@app
+ else
+ ActionDispatch.test_app
+ end
end
def app=(app)
diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb
index 5298e63fef..cac89417a5 100644
--- a/actionpack/test/dispatch/routing_test.rb
+++ b/actionpack/test/dispatch/routing_test.rb
@@ -1759,6 +1759,24 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
assert_equal 1, @request.params[:page]
end
+ def test_keyed_default_string_params_with_root
+ draw do
+ root to: 'pages#show', defaults: { id: 'home' }
+ end
+
+ get '/'
+ assert_equal 'home', @request.params[:id]
+ end
+
+ def test_default_string_params_with_root
+ draw do
+ root to: 'pages#show', id: 'home'
+ end
+
+ get '/'
+ assert_equal 'home', @request.params[:id]
+ end
+
def test_resource_constraints
draw do
resources :products, :constraints => { :id => /\d{4}/ } do
diff --git a/actionview/CHANGELOG.md b/actionview/CHANGELOG.md
index ab4b46c56e..7754bd8dd9 100644
--- a/actionview/CHANGELOG.md
+++ b/actionview/CHANGELOG.md
@@ -1,3 +1,14 @@
+* Changed partial rendering with a collection to allow collections which
+ implement `to_a`.
+
+ Extracting the collection option had an optimization to avoid unnecessary
+ queries of ActiveRecord Relations by calling `#to_ary` on the given
+ collection. Instances of `Enumerator` or `Enumerable` are valid
+ collections, but they do not implement `#to_ary`. By changing this to
+ `#to_a`, they will now be extracted and rendered as expected.
+
+ *Steven Harman*
+
* New syntax for tag helpers. Avoid positional parameters and support HTML5 by default.
Example usage of tag helpers before:
diff --git a/actionview/lib/action_view/helpers/asset_tag_helper.rb b/actionview/lib/action_view/helpers/asset_tag_helper.rb
index bcbb3db6a9..d7acf08b45 100644
--- a/actionview/lib/action_view/helpers/asset_tag_helper.rb
+++ b/actionview/lib/action_view/helpers/asset_tag_helper.rb
@@ -1,5 +1,6 @@
require 'active_support/core_ext/array/extract_options'
require 'active_support/core_ext/hash/keys'
+require 'active_support/core_ext/regexp'
require 'action_view/helpers/asset_url_helper'
require 'action_view/helpers/tag_helper'
@@ -213,8 +214,8 @@ module ActionView
src = options[:src] = path_to_image(source)
- unless src =~ /^(?:cid|data):/ || src.blank?
- options[:alt] = options.fetch(:alt){ image_alt(src) }
+ unless src.start_with?('cid:') || src.start_with?('data:') || src.blank?
+ options[:alt] = options.fetch(:alt) { image_alt(src) }
end
options[:width], options[:height] = extract_dimensions(options.delete(:size)) if options[:size]
@@ -322,9 +323,9 @@ module ActionView
def extract_dimensions(size)
size = size.to_s
- if size =~ %r{\A\d+x\d+\z}
+ if /\A\d+x\d+\z/.match?(size)
size.split('x')
- elsif size =~ %r{\A\d+\z}
+ elsif /\A\d+\z/.match?(size)
[size, size]
end
end
diff --git a/actionview/lib/action_view/helpers/asset_url_helper.rb b/actionview/lib/action_view/helpers/asset_url_helper.rb
index 717b326740..8af01617fa 100644
--- a/actionview/lib/action_view/helpers/asset_url_helper.rb
+++ b/actionview/lib/action_view/helpers/asset_url_helper.rb
@@ -1,4 +1,5 @@
require 'zlib'
+require 'active_support/core_ext/regexp'
module ActionView
# = Action View Asset URL Helpers
@@ -131,8 +132,8 @@ module ActionView
raise ArgumentError, "nil is not a valid asset source" if source.nil?
source = source.to_s
- return "" unless source.present?
- return source if source =~ URI_REGEXP
+ return '' if source.blank?
+ return source if URI_REGEXP.match?(source)
tail, source = source[/([\?#].+)$/], source.sub(/([\?#].+)$/, ''.freeze)
@@ -213,19 +214,21 @@ module ActionView
host = options[:host]
host ||= config.asset_host if defined? config.asset_host
- if host.respond_to?(:call)
- arity = host.respond_to?(:arity) ? host.arity : host.method(:call).arity
- args = [source]
- args << request if request && (arity > 1 || arity < 0)
- host = host.call(*args)
- elsif host =~ /%d/
- host = host % (Zlib.crc32(source) % 4)
+ if host
+ if host.respond_to?(:call)
+ arity = host.respond_to?(:arity) ? host.arity : host.method(:call).arity
+ args = [source]
+ args << request if request && (arity > 1 || arity < 0)
+ host = host.call(*args)
+ elsif host.include?('%d')
+ host = host % (Zlib.crc32(source) % 4)
+ end
end
host ||= request.base_url if request && options[:protocol] == :request
return unless host
- if host =~ URI_REGEXP
+ if URI_REGEXP.match?(host)
host
else
protocol = options[:protocol] || config.default_asset_host_protocol || (request ? :request : :relative)
diff --git a/actionview/lib/action_view/helpers/translation_helper.rb b/actionview/lib/action_view/helpers/translation_helper.rb
index 152e1b1211..622bb193ae 100644
--- a/actionview/lib/action_view/helpers/translation_helper.rb
+++ b/actionview/lib/action_view/helpers/translation_helper.rb
@@ -1,5 +1,6 @@
require 'action_view/helpers/tag_helper'
require 'active_support/core_ext/string/access'
+require 'active_support/core_ext/regexp'
require 'i18n/exceptions'
module ActionView
@@ -133,7 +134,7 @@ module ActionView
end
def html_safe_translation_key?(key)
- key.to_s =~ /(\b|_|\.)html$/
+ /(\b|_|\.)html$/.match?(key.to_s)
end
end
end
diff --git a/actionview/lib/action_view/helpers/url_helper.rb b/actionview/lib/action_view/helpers/url_helper.rb
index fb6426b997..5d7940a7b1 100644
--- a/actionview/lib/action_view/helpers/url_helper.rb
+++ b/actionview/lib/action_view/helpers/url_helper.rb
@@ -2,6 +2,7 @@ require 'action_view/helpers/javascript_helper'
require 'active_support/core_ext/array/access'
require 'active_support/core_ext/hash/keys'
require 'active_support/core_ext/string/output_safety'
+require 'active_support/core_ext/regexp'
module ActionView
# = Action View URL Helpers
@@ -550,7 +551,7 @@ module ActionView
url_string.chomp!("/") if url_string.start_with?("/") && url_string != "/"
- if url_string =~ /^\w+:\/\//
+ if %r{^\w+://}.match?(url_string)
url_string == "#{request.protocol}#{request.host_with_port}#{request_uri}"
else
url_string == request_uri
diff --git a/actionview/lib/action_view/layouts.rb b/actionview/lib/action_view/layouts.rb
index 8db1674187..8e956c47c6 100644
--- a/actionview/lib/action_view/layouts.rb
+++ b/actionview/lib/action_view/layouts.rb
@@ -1,5 +1,6 @@
-require "action_view/rendering"
-require "active_support/core_ext/module/remove_method"
+require 'action_view/rendering'
+require 'active_support/core_ext/module/remove_method'
+require 'active_support/core_ext/regexp'
module ActionView
# Layouts reverse the common pattern of including shared headers and footers in many templates to isolate changes in
@@ -279,7 +280,7 @@ module ActionView
def _write_layout_method # :nodoc:
remove_possible_method(:_layout)
- prefixes = _implied_layout_name =~ /\blayouts/ ? [] : ["layouts"]
+ prefixes = /\blayouts/.match?(_implied_layout_name) ? [] : ["layouts"]
default_behavior = "lookup_context.find_all('#{_implied_layout_name}', #{prefixes.inspect}, false, [], { formats: formats }).first || super"
name_clause = if name
default_behavior
diff --git a/actionview/lib/action_view/renderer/partial_renderer.rb b/actionview/lib/action_view/renderer/partial_renderer.rb
index 13b4ec6133..7c2e07185c 100644
--- a/actionview/lib/action_view/renderer/partial_renderer.rb
+++ b/actionview/lib/action_view/renderer/partial_renderer.rb
@@ -1,5 +1,6 @@
-require 'action_view/renderer/partial_renderer/collection_caching'
require 'concurrent/map'
+require 'active_support/core_ext/regexp'
+require 'action_view/renderer/partial_renderer/collection_caching'
module ActionView
class PartialIteration
@@ -386,7 +387,7 @@ module ActionView
end
if as = options[:as]
- raise_invalid_option_as(as) unless as.to_s =~ /\A[a-z_]\w*\z/
+ raise_invalid_option_as(as) unless /\A[a-z_]\w*\z/.match?(as.to_s)
as = as.to_sym
end
@@ -403,7 +404,7 @@ module ActionView
def collection_from_options
if @options.key?(:collection)
collection = @options[:collection]
- collection.respond_to?(:to_ary) ? collection.to_ary : []
+ collection ? collection.to_a : []
end
end
diff --git a/actionview/lib/action_view/renderer/template_renderer.rb b/actionview/lib/action_view/renderer/template_renderer.rb
index 1d6afb90fe..9b106cd64a 100644
--- a/actionview/lib/action_view/renderer/template_renderer.rb
+++ b/actionview/lib/action_view/renderer/template_renderer.rb
@@ -83,7 +83,7 @@ module ActionView
case layout
when String
begin
- if layout =~ /^\//
+ if layout.start_with?('/')
with_fallbacks { find_template(layout, nil, false, [], details) }
else
find_template(layout, nil, false, [], details)
diff --git a/actionview/lib/action_view/template/error.rb b/actionview/lib/action_view/template/error.rb
index 3f38c3d2b9..0f1348b032 100644
--- a/actionview/lib/action_view/template/error.rb
+++ b/actionview/lib/action_view/template/error.rb
@@ -1,4 +1,5 @@
require "active_support/core_ext/enumerable"
+require 'active_support/core_ext/regexp'
module ActionView
# = Action View Errors
@@ -35,7 +36,7 @@ module ActionView
prefixes = Array(prefixes)
template_type = if partial
"partial"
- elsif path =~ /layouts/i
+ elsif /layouts/i.match?(path)
'layout'
else
'template'
diff --git a/actionview/lib/action_view/template/handlers/erb.rb b/actionview/lib/action_view/template/handlers/erb.rb
index 85a100ed4c..058b590c56 100644
--- a/actionview/lib/action_view/template/handlers/erb.rb
+++ b/actionview/lib/action_view/template/handlers/erb.rb
@@ -1,4 +1,5 @@
require 'erubis'
+require 'active_support/core_ext/regexp'
module ActionView
class Template
@@ -39,7 +40,7 @@ module ActionView
def add_expr_literal(src, code)
flush_newline_if_pending(src)
- if code =~ BLOCK_EXPR
+ if BLOCK_EXPR.match?(code)
src << '@output_buffer.append= ' << code
else
src << '@output_buffer.append=(' << code << ');'
@@ -48,7 +49,7 @@ module ActionView
def add_expr_escaped(src, code)
flush_newline_if_pending(src)
- if code =~ BLOCK_EXPR
+ if BLOCK_EXPR.match?(code)
src << "@output_buffer.safe_expr_append= " << code
else
src << "@output_buffer.safe_expr_append=(" << code << ");"
diff --git a/actionview/lib/action_view/testing/resolvers.rb b/actionview/lib/action_view/testing/resolvers.rb
index 2664aca991..982ecf9efc 100644
--- a/actionview/lib/action_view/testing/resolvers.rb
+++ b/actionview/lib/action_view/testing/resolvers.rb
@@ -1,3 +1,4 @@
+require 'active_support/core_ext/regexp'
require 'action_view/template/resolver'
module ActionView #:nodoc:
@@ -29,7 +30,7 @@ module ActionView #:nodoc:
templates = []
@hash.each do |_path, array|
source, updated_at = array
- next unless _path =~ query
+ next unless query.match?(_path)
handler, format, variant = extract_handler_and_format_and_variant(_path, formats)
templates << Template.new(source, _path, handler,
:virtual_path => path.virtual,
@@ -50,4 +51,3 @@ module ActionView #:nodoc:
end
end
end
-
diff --git a/actionview/test/actionpack/controller/layout_test.rb b/actionview/test/actionpack/controller/layout_test.rb
index 64bc4c41d6..ecfef3dc8c 100644
--- a/actionview/test/actionpack/controller/layout_test.rb
+++ b/actionview/test/actionpack/controller/layout_test.rb
@@ -1,5 +1,6 @@
require 'abstract_unit'
require 'active_support/core_ext/array/extract_options'
+require 'active_support/core_ext/regexp'
# The view_paths array must be set on Base and not LayoutTest so that LayoutTest's inherited
# method has access to the view_paths array when looking for a layout to automatically assign.
@@ -252,7 +253,7 @@ class LayoutStatusIsRenderedTest < ActionController::TestCase
end
end
-unless RbConfig::CONFIG['host_os'] =~ /mswin|mingw/
+unless /mswin|mingw/.match?(RbConfig::CONFIG['host_os'])
class LayoutSymlinkedTest < LayoutTest
layout "symlinked/symlinked_layout"
end
diff --git a/actionview/test/template/render_test.rb b/actionview/test/template/render_test.rb
index 25b21850b1..68574d4adb 100644
--- a/actionview/test/template/render_test.rb
+++ b/actionview/test/template/render_test.rb
@@ -309,6 +309,14 @@ module RenderTestCases
assert_nil @view.render(:partial => "test/customer", :collection => nil)
end
+ def test_render_partial_collection_for_non_array
+ customers = Enumerator.new do |y|
+ y.yield(Customer.new("david"))
+ y.yield(Customer.new("mary"))
+ end
+ assert_equal "Hello: davidHello: mary", @view.render(partial: "test/customer", collection: customers)
+ end
+
def test_render_partial_without_object_does_not_put_partial_name_to_local_assigns
assert_equal 'false', @view.render(partial: 'test/partial_name_in_local_assigns')
end
diff --git a/activejob/lib/active_job/core.rb b/activejob/lib/active_job/core.rb
index f7f882c998..f0606b3834 100644
--- a/activejob/lib/active_job/core.rb
+++ b/activejob/lib/active_job/core.rb
@@ -105,6 +105,7 @@ module ActiveJob
# end
def deserialize(job_data)
self.job_id = job_data['job_id']
+ self.provider_job_id = job_data['provider_job_id']
self.queue_name = job_data['queue_name']
self.priority = job_data['priority']
self.serialized_arguments = job_data['arguments']
diff --git a/activejob/lib/active_job/queue_adapters/sidekiq_adapter.rb b/activejob/lib/active_job/queue_adapters/sidekiq_adapter.rb
index c321776bf5..3d33b3923b 100644
--- a/activejob/lib/active_job/queue_adapters/sidekiq_adapter.rb
+++ b/activejob/lib/active_job/queue_adapters/sidekiq_adapter.rb
@@ -37,7 +37,7 @@ module ActiveJob
include Sidekiq::Worker
def perform(job_data)
- Base.execute job_data
+ Base.execute job_data.merge('provider_job_id' => jid)
end
end
end
diff --git a/activejob/test/integration/queuing_test.rb b/activejob/test/integration/queuing_test.rb
index 40f27500a5..ab3de3a8b9 100644
--- a/activejob/test/integration/queuing_test.rb
+++ b/activejob/test/integration/queuing_test.rb
@@ -1,6 +1,7 @@
require 'helper'
require 'jobs/logging_job'
require 'jobs/hello_job'
+require 'jobs/provider_jid_job'
require 'active_support/core_ext/numeric/time'
class QueuingTest < ActiveSupport::TestCase
@@ -34,6 +35,14 @@ class QueuingTest < ActiveSupport::TestCase
end
end
+ test 'should access provider_job_id inside Sidekiq job' do
+ skip unless adapter_is?(:sidekiq)
+ Sidekiq::Testing.inline! do
+ job = ::ProviderJidJob.perform_later
+ assert_equal "Provider Job ID: #{job.provider_job_id}", JobBuffer.last_value
+ end
+ end
+
test 'should not run job enqueued in the future' do
begin
TestJob.set(wait: 10.minutes).perform_later @id
diff --git a/activejob/test/jobs/provider_jid_job.rb b/activejob/test/jobs/provider_jid_job.rb
new file mode 100644
index 0000000000..e4f585fa94
--- /dev/null
+++ b/activejob/test/jobs/provider_jid_job.rb
@@ -0,0 +1,7 @@
+require_relative '../support/job_buffer'
+
+class ProviderJidJob < ActiveJob::Base
+ def perform
+ JobBuffer.add("Provider Job ID: #{provider_job_id}")
+ end
+end
diff --git a/activemodel/lib/active_model/attribute_methods.rb b/activemodel/lib/active_model/attribute_methods.rb
index cc6285f932..140eb9420e 100644
--- a/activemodel/lib/active_model/attribute_methods.rb
+++ b/activemodel/lib/active_model/attribute_methods.rb
@@ -1,5 +1,6 @@
require 'concurrent/map'
require 'mutex_m'
+require 'active_support/core_ext/regexp'
module ActiveModel
# Raised when an attribute is not defined.
@@ -366,7 +367,7 @@ module ActiveModel
# using the given `extra` args. This falls back on `define_method`
# and `send` if the given names cannot be compiled.
def define_proxy_call(include_private, mod, name, send, *extra) #:nodoc:
- defn = if name =~ NAME_COMPILABLE_REGEXP
+ defn = if NAME_COMPILABLE_REGEXP.match?(name)
"def #{name}(*args)"
else
"define_method(:'#{name}') do |*args|"
@@ -374,7 +375,7 @@ module ActiveModel
extra = (extra.map!(&:inspect) << "*args").join(", ".freeze)
- target = if send =~ CALL_COMPILABLE_REGEXP
+ target = if CALL_COMPILABLE_REGEXP.match?(send)
"#{"self." unless include_private}#{send}(#{extra})"
else
"send(:'#{send}', #{extra})"
diff --git a/activemodel/lib/active_model/type/time.rb b/activemodel/lib/active_model/type/time.rb
index 34e09f0aba..08d127d187 100644
--- a/activemodel/lib/active_model/type/time.rb
+++ b/activemodel/lib/active_model/type/time.rb
@@ -29,7 +29,7 @@ module ActiveModel
return value unless value.is_a?(::String)
return if value.empty?
- if value =~ /^2000-01-01/
+ if value.start_with?('2000-01-01')
dummy_time_value = value
else
dummy_time_value = "2000-01-01 #{value}"
diff --git a/activemodel/lib/active_model/validations/format.rb b/activemodel/lib/active_model/validations/format.rb
index 46a2e54fba..70799aaf23 100644
--- a/activemodel/lib/active_model/validations/format.rb
+++ b/activemodel/lib/active_model/validations/format.rb
@@ -1,5 +1,6 @@
-module ActiveModel
+require 'active_support/core_ext/regexp'
+module ActiveModel
module Validations
class FormatValidator < EachValidator # :nodoc:
def validate_each(record, attribute, value)
@@ -8,7 +9,7 @@ module ActiveModel
record_error(record, attribute, :with, value) if value.to_s !~ regexp
elsif options[:without]
regexp = option_call(record, :without)
- record_error(record, attribute, :without, value) if value.to_s =~ regexp
+ record_error(record, attribute, :without, value) if regexp.match?(value.to_s)
end
end
diff --git a/activemodel/test/validators/email_validator.rb b/activemodel/test/validators/email_validator.rb
index cff47ac230..5dc1fc5ae2 100644
--- a/activemodel/test/validators/email_validator.rb
+++ b/activemodel/test/validators/email_validator.rb
@@ -1,6 +1,8 @@
+require 'active_support/core_ext/regexp'
+
class EmailValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
record.errors[attribute] << (options[:message] || "is not an email") unless
- value =~ /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
+ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i.match?(value)
end
-end \ No newline at end of file
+end
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index 590fe2f587..14a6c3c9f7 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,12 @@
+* Fix the SELECT statement in `#table_comment` for MySQL.
+
+ *Takeshi Akima*
+
+* Virtual attributes will no longer raise when read on models loaded from the
+ database
+
+ *Sean Griffin*
+
* Support calling the method `merge` in `scope`'s lambda.
*Yasuhiro Sugino*
diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb
index 56dee10df2..806a905323 100644
--- a/activerecord/lib/active_record/associations/collection_proxy.rb
+++ b/activerecord/lib/active_record/associations/collection_proxy.rb
@@ -1070,6 +1070,12 @@ module ActiveRecord
proxy_association.reset_scope
self
end
+
+ private
+
+ def exec_queries
+ load_target
+ end
end
end
end
diff --git a/activerecord/lib/active_record/associations/has_one_through_association.rb b/activerecord/lib/active_record/associations/has_one_through_association.rb
index 08e0ec691f..604904abcc 100644
--- a/activerecord/lib/active_record/associations/has_one_through_association.rb
+++ b/activerecord/lib/active_record/associations/has_one_through_association.rb
@@ -15,7 +15,7 @@ module ActiveRecord
ensure_not_nested
through_proxy = owner.association(through_reflection.name)
- through_record = through_proxy.send(:load_target)
+ through_record = through_proxy.load_target
if through_record && !record
through_record.destroy
diff --git a/activerecord/lib/active_record/associations/join_dependency/join_association.rb b/activerecord/lib/active_record/associations/join_dependency/join_association.rb
index c5fbe0d1d1..bdf77009eb 100644
--- a/activerecord/lib/active_record/associations/join_dependency/join_association.rb
+++ b/activerecord/lib/active_record/associations/join_dependency/join_association.rb
@@ -56,7 +56,9 @@ module ActiveRecord
klass_scope =
if klass.current_scope
- klass.current_scope.clone
+ klass.current_scope.clone.tap { |scope|
+ scope.joins_values = []
+ }
else
relation = ActiveRecord::Relation.create(
klass,
diff --git a/activerecord/lib/active_record/attribute.rb b/activerecord/lib/active_record/attribute.rb
index 9530f134d0..2f41e9e45b 100644
--- a/activerecord/lib/active_record/attribute.rb
+++ b/activerecord/lib/active_record/attribute.rb
@@ -152,7 +152,7 @@ module ActiveRecord
end
def _original_value_for_database
- value_for_database
+ type.serialize(original_value)
end
class FromDatabase < Attribute # :nodoc:
@@ -180,7 +180,7 @@ module ActiveRecord
value
end
- def changed_in_place_from?(old_value)
+ def changed_in_place?
false
end
end
diff --git a/activerecord/lib/active_record/attribute_set.rb b/activerecord/lib/active_record/attribute_set.rb
index 720d5f8b7c..f868f23845 100644
--- a/activerecord/lib/active_record/attribute_set.rb
+++ b/activerecord/lib/active_record/attribute_set.rb
@@ -3,7 +3,7 @@ require 'active_record/attribute_set/yaml_encoder'
module ActiveRecord
class AttributeSet # :nodoc:
- delegate :each_value, to: :attributes
+ delegate :each_value, :fetch, to: :attributes
def initialize(attributes)
@attributes = attributes
diff --git a/activerecord/lib/active_record/attribute_set/builder.rb b/activerecord/lib/active_record/attribute_set/builder.rb
index 24a255efc1..4ffd39d82d 100644
--- a/activerecord/lib/active_record/attribute_set/builder.rb
+++ b/activerecord/lib/active_record/attribute_set/builder.rb
@@ -3,11 +3,12 @@ require 'active_record/attribute'
module ActiveRecord
class AttributeSet # :nodoc:
class Builder # :nodoc:
- attr_reader :types, :always_initialized
+ attr_reader :types, :always_initialized, :default
- def initialize(types, always_initialized = nil)
+ def initialize(types, always_initialized = nil, &default)
@types = types
@always_initialized = always_initialized
+ @default = default
end
def build_from_database(values = {}, additional_types = {})
@@ -15,21 +16,22 @@ module ActiveRecord
values[always_initialized] = nil
end
- attributes = LazyAttributeHash.new(types, values, additional_types)
+ attributes = LazyAttributeHash.new(types, values, additional_types, &default)
AttributeSet.new(attributes)
end
end
end
class LazyAttributeHash # :nodoc:
- delegate :transform_values, :each_key, :each_value, to: :materialize
+ delegate :transform_values, :each_key, :each_value, :fetch, to: :materialize
- def initialize(types, values, additional_types)
+ def initialize(types, values, additional_types, &default)
@types = types
@values = values
@additional_types = additional_types
@materialized = false
@delegate_hash = {}
+ @default = default || proc {}
end
def key?(key)
@@ -76,9 +78,21 @@ module ActiveRecord
end
end
+ def marshal_dump
+ materialize
+ end
+
+ def marshal_load(delegate_hash)
+ @delegate_hash = delegate_hash
+ @types = {}
+ @values = {}
+ @additional_types = {}
+ @materialized = true
+ end
+
protected
- attr_reader :types, :values, :additional_types, :delegate_hash
+ attr_reader :types, :values, :additional_types, :delegate_hash, :default
def materialize
unless @materialized
@@ -101,7 +115,7 @@ module ActiveRecord
if value_present
delegate_hash[name] = Attribute.from_database(name, value, type)
elsif types.key?(name)
- delegate_hash[name] = Attribute.uninitialized(name, type)
+ delegate_hash[name] = default.call(name) || Attribute.uninitialized(name, type)
end
end
end
diff --git a/activerecord/lib/active_record/attributes.rb b/activerecord/lib/active_record/attributes.rb
index 3211b6eaeb..ed0302e763 100644
--- a/activerecord/lib/active_record/attributes.rb
+++ b/activerecord/lib/active_record/attributes.rb
@@ -253,7 +253,7 @@ module ActiveRecord
name,
value,
type,
- _default_attributes[name],
+ _default_attributes.fetch(name.to_s) { nil },
)
else
default_attribute = Attribute.from_database(name, value, type)
diff --git a/activerecord/lib/active_record/coders/yaml_column.rb b/activerecord/lib/active_record/coders/yaml_column.rb
index 606abb7e24..5ac1e0c001 100644
--- a/activerecord/lib/active_record/coders/yaml_column.rb
+++ b/activerecord/lib/active_record/coders/yaml_column.rb
@@ -1,4 +1,5 @@
require 'yaml'
+require 'active_support/core_ext/regexp'
module ActiveRecord
module Coders # :nodoc:
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 74aae3a1e4..e667e16964 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
@@ -18,11 +18,12 @@ module ActiveRecord
# This is used in the StatementCache object. It returns an object that
# can be used to query the database repeatedly.
- def cacheable_query(arel) # :nodoc:
+ def cacheable_query(klass, arel) # :nodoc:
+ collected = visitor.accept(arel.ast, collector)
if prepared_statements
- ActiveRecord::StatementCache.query visitor, arel.ast
+ klass.query(collected.value)
else
- ActiveRecord::StatementCache.partial_query visitor, arel.ast, collector
+ klass.partial_query(collected.value)
end
end
@@ -315,7 +316,7 @@ module ActiveRecord
end
end
key_list = fixture.keys.map { |name| quote_column_name(name) }
- value_list = prepare_binds_for_database(binds).map do |value|
+ value_list = binds.map(&:value_for_database).map do |value|
begin
quote(value)
rescue TypeError
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
index 860ef17dca..eda6af08e3 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
@@ -112,19 +112,19 @@ module ActiveRecord
end
def quoted_true
- "'t'"
+ "'t'".freeze
end
def unquoted_true
- 't'
+ 't'.freeze
end
def quoted_false
- "'f'"
+ "'f'".freeze
end
def unquoted_false
- 'f'
+ 'f'.freeze
end
# Quote date/time values for use in SQL input. Includes microseconds
@@ -150,12 +150,12 @@ module ActiveRecord
quoted_date(value).sub(/\A2000-01-01 /, '')
end
- def prepare_binds_for_database(binds) # :nodoc:
- binds.map(&:value_for_database)
- end
-
private
+ def type_casted_binds(binds)
+ binds.map { |attr| type_cast(attr.value_for_database) }
+ end
+
def types_which_need_no_typecasting
[nil, Numeric, String]
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
index 4f8490fa2b..0b8bacff4e 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
@@ -130,7 +130,7 @@ module ActiveRecord
class BindCollector < Arel::Collectors::Bind
def compile(bvs, conn)
- casted_binds = conn.prepare_binds_for_database(bvs)
+ casted_binds = bvs.map(&:value_for_database)
super(casted_binds.map { |value| conn.quote(value) })
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
index 0a98a8e9c1..610d78245f 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
@@ -9,6 +9,7 @@ require 'active_record/connection_adapters/mysql/schema_dumper'
require 'active_record/connection_adapters/mysql/type_metadata'
require 'active_support/core_ext/string/strip'
+require 'active_support/core_ext/regexp'
module ActiveRecord
module ConnectionAdapters
@@ -409,10 +410,13 @@ module ActiveRecord
end
def table_comment(table_name) # :nodoc:
+ schema, name = extract_schema_qualified_name(table_name)
+
select_value(<<-SQL.strip_heredoc, 'SCHEMA')
SELECT table_comment
FROM information_schema.tables
- WHERE table_name=#{quote(table_name)}
+ WHERE table_schema = #{quote(schema)}
+ AND table_name = #{quote(name)}
SQL
end
@@ -543,7 +547,9 @@ module ActiveRecord
end
end
- def table_options(table_name)
+ def table_options(table_name) # :nodoc:
+ table_options = {}
+
create_table_info = create_table_info(table_name)
# strip create_definitions and partition_options
@@ -552,10 +558,14 @@ module ActiveRecord
# strip AUTO_INCREMENT
raw_table_options.sub!(/(ENGINE=\w+)(?: AUTO_INCREMENT=\d+)/, '\1')
+ table_options[:options] = raw_table_options
+
# strip COMMENT
- raw_table_options.sub!(/ COMMENT='.+'/, '')
+ if raw_table_options.sub!(/ COMMENT='.+'/, '')
+ table_options[:comment] = table_comment(table_name)
+ end
- raw_table_options
+ table_options
end
# Maps logical Rails types to MySQL-specific data types.
diff --git a/activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb b/activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb
index cc19d95669..6d1215df2a 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb
@@ -77,7 +77,7 @@ module ActiveRecord
@connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone
end
- type_casted_binds = binds.map { |attr| type_cast(attr.value_for_database) }
+ type_casted_binds = type_casted_binds(binds)
log(sql, name, binds, type_casted_binds) do
if cache_stmt
diff --git a/activerecord/lib/active_record/connection_adapters/mysql/quoting.rb b/activerecord/lib/active_record/connection_adapters/mysql/quoting.rb
index fbab654112..af1db30047 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql/quoting.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql/quoting.rb
@@ -2,14 +2,14 @@ module ActiveRecord
module ConnectionAdapters
module MySQL
module Quoting # :nodoc:
- QUOTED_TRUE, QUOTED_FALSE = '1', '0'
+ QUOTED_TRUE, QUOTED_FALSE = '1'.freeze, '0'.freeze
def quote_column_name(name)
- @quoted_column_names[name] ||= "`#{super.gsub('`', '``')}`"
+ @quoted_column_names[name] ||= "`#{super.gsub('`', '``')}`".freeze
end
def quote_table_name(name)
- @quoted_table_names[name] ||= super.gsub('.', '`.`')
+ @quoted_table_names[name] ||= super.gsub('.', '`.`').freeze
end
def quoted_true
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb
index 80c219dfd7..9fcf8dbb95 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb
@@ -28,7 +28,7 @@ module ActiveRecord
# - "schema.name".table_name
# - "schema.name"."table.name"
def quote_table_name(name) # :nodoc:
- @quoted_table_names[name] ||= Utils.extract_schema_qualified_name(name.to_s).quoted
+ @quoted_table_names[name] ||= Utils.extract_schema_qualified_name(name.to_s).quoted.freeze
end
# Quotes schema names for use in SQL queries.
@@ -42,7 +42,7 @@ module ActiveRecord
# Quotes column names for use in SQL queries.
def quote_column_name(name) # :nodoc:
- @quoted_column_names[name] ||= PGconn.quote_ident(super)
+ @quoted_column_names[name] ||= PGconn.quote_ident(super).freeze
end
# Quote date/time values for use in SQL input.
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 cc606e4828..4cf6d4b14a 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
@@ -238,6 +238,10 @@ module ActiveRecord
PostgreSQLColumn.new(*args)
end
+ def table_options(table_name) # :nodoc:
+ { comment: table_comment(table_name) }
+ end
+
# Returns a comment stored in database for given table
def table_comment(table_name) # :nodoc:
name = Utils.extract_schema_qualified_name(table_name.to_s)
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index 487165d511..61a980fda9 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -597,13 +597,13 @@ module ActiveRecord
end
def exec_no_cache(sql, name, binds)
- type_casted_binds = binds.map { |attr| type_cast(attr.value_for_database) }
+ type_casted_binds = type_casted_binds(binds)
log(sql, name, binds, type_casted_binds) { @connection.async_exec(sql, type_casted_binds) }
end
def exec_cache(sql, name, binds)
stmt_key = prepare_statement(sql)
- type_casted_binds = binds.map { |attr| type_cast(attr.value_for_database) }
+ type_casted_binds = type_casted_binds(binds)
log(sql, name, binds, type_casted_binds, stmt_key) do
@connection.exec_prepared(stmt_key, type_casted_binds)
diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3/quoting.rb b/activerecord/lib/active_record/connection_adapters/sqlite3/quoting.rb
index d5a181d3e2..fa20175b0e 100644
--- a/activerecord/lib/active_record/connection_adapters/sqlite3/quoting.rb
+++ b/activerecord/lib/active_record/connection_adapters/sqlite3/quoting.rb
@@ -11,7 +11,7 @@ module ActiveRecord
end
def quote_column_name(name)
- @quoted_column_names[name] ||= %Q("#{super.gsub('"', '""')}")
+ @quoted_column_names[name] ||= %Q("#{super.gsub('"', '""')}").freeze
end
def quoted_time(value)
diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
index ed6bff4665..41ed784d2e 100644
--- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
@@ -188,7 +188,7 @@ module ActiveRecord
end
def exec_query(sql, name = nil, binds = [], prepare: false)
- type_casted_binds = binds.map { |attr| type_cast(attr.value_for_database) }
+ type_casted_binds = type_casted_binds(binds)
log(sql, name, binds, type_casted_binds) do
# Don't cache statements if they are not prepared
@@ -203,7 +203,6 @@ module ActiveRecord
ensure
stmt.close
end
- stmt = records
else
cache = @statements[sql] ||= {
:stmt => @connection.prepare(sql)
@@ -212,9 +211,10 @@ module ActiveRecord
cols = cache[:cols] ||= stmt.columns
stmt.reset!
stmt.bind_params(type_casted_binds)
+ records = stmt.to_a
end
- ActiveRecord::Result.new(cols, stmt.to_a)
+ ActiveRecord::Result.new(cols, records)
end
end
diff --git a/activerecord/lib/active_record/dynamic_matchers.rb b/activerecord/lib/active_record/dynamic_matchers.rb
index 88cb66d977..0bdebb3989 100644
--- a/activerecord/lib/active_record/dynamic_matchers.rb
+++ b/activerecord/lib/active_record/dynamic_matchers.rb
@@ -1,3 +1,5 @@
+require 'active_support/core_ext/regexp'
+
module ActiveRecord
module DynamicMatchers #:nodoc:
def respond_to?(name, include_private = false)
diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb
index 1ad209cbbf..1bb4688717 100644
--- a/activerecord/lib/active_record/migration.rb
+++ b/activerecord/lib/active_record/migration.rb
@@ -1,5 +1,6 @@
-require "active_support/core_ext/module/attribute_accessors"
require 'set'
+require "active_support/core_ext/module/attribute_accessors"
+require 'active_support/core_ext/regexp'
module ActiveRecord
class MigrationError < ActiveRecordError#:nodoc:
diff --git a/activerecord/lib/active_record/model_schema.rb b/activerecord/lib/active_record/model_schema.rb
index 99facb4b25..41cebb0e34 100644
--- a/activerecord/lib/active_record/model_schema.rb
+++ b/activerecord/lib/active_record/model_schema.rb
@@ -249,7 +249,11 @@ module ActiveRecord
end
def attributes_builder # :nodoc:
- @attributes_builder ||= AttributeSet::Builder.new(attribute_types, primary_key)
+ @attributes_builder ||= AttributeSet::Builder.new(attribute_types, primary_key) do |name|
+ unless columns_hash.key?(name)
+ _default_attributes[name].dup
+ end
+ end
end
def columns_hash # :nodoc:
diff --git a/activerecord/lib/active_record/relation/delegation.rb b/activerecord/lib/active_record/relation/delegation.rb
index 13f80270a4..ad74659cba 100644
--- a/activerecord/lib/active_record/relation/delegation.rb
+++ b/activerecord/lib/active_record/relation/delegation.rb
@@ -1,4 +1,5 @@
require 'active_support/concern'
+require 'active_support/core_ext/regexp'
module ActiveRecord
module Delegation # :nodoc:
diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb
index 62821cacc9..0749bb30b5 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -4,6 +4,7 @@ require "active_record/relation/where_clause"
require "active_record/relation/where_clause_factory"
require 'active_model/forbidden_attributes_protection'
require 'active_support/core_ext/string/filters'
+require 'active_support/core_ext/regexp'
module ActiveRecord
module QueryMethods
diff --git a/activerecord/lib/active_record/sanitization.rb b/activerecord/lib/active_record/sanitization.rb
index 6ecb9ce3a7..f007e9e733 100644
--- a/activerecord/lib/active_record/sanitization.rb
+++ b/activerecord/lib/active_record/sanitization.rb
@@ -1,3 +1,5 @@
+require 'active_support/core_ext/regexp'
+
module ActiveRecord
module Sanitization
extend ActiveSupport::Concern
diff --git a/activerecord/lib/active_record/schema_dumper.rb b/activerecord/lib/active_record/schema_dumper.rb
index e8c176d603..cc3bb1cd06 100644
--- a/activerecord/lib/active_record/schema_dumper.rb
+++ b/activerecord/lib/active_record/schema_dumper.rb
@@ -127,10 +127,10 @@ HEADER
tbl.print ", force: :cascade"
table_options = @connection.table_options(table)
- tbl.print ", options: #{table_options.inspect}" unless table_options.blank?
-
- if comment = @connection.table_comment(table).presence
- tbl.print ", comment: #{comment.inspect}"
+ if table_options.present?
+ table_options.each do |key, value|
+ tbl.print ", #{key}: #{value.inspect}" if value.present?
+ end
end
tbl.puts " do |t|"
diff --git a/activerecord/lib/active_record/statement_cache.rb b/activerecord/lib/active_record/statement_cache.rb
index 6c896ccea6..8a29547bda 100644
--- a/activerecord/lib/active_record/statement_cache.rb
+++ b/activerecord/lib/active_record/statement_cache.rb
@@ -40,7 +40,7 @@ module ActiveRecord
end
class PartialQuery < Query # :nodoc:
- def initialize values
+ def initialize(values)
@values = values
@indexes = values.each_with_index.find_all { |thing,i|
Arel::Nodes::BindParam === thing
@@ -49,19 +49,18 @@ module ActiveRecord
def sql_for(binds, connection)
val = @values.dup
- binds = connection.prepare_binds_for_database(binds)
- @indexes.each { |i| val[i] = connection.quote(binds.shift) }
+ casted_binds = binds.map(&:value_for_database)
+ @indexes.each { |i| val[i] = connection.quote(casted_binds.shift) }
val.join
end
end
- def self.query(visitor, ast)
- Query.new visitor.accept(ast, Arel::Collectors::SQLString.new).value
+ def self.query(sql)
+ Query.new(sql)
end
- def self.partial_query(visitor, ast, collector)
- collected = visitor.accept(ast, collector).value
- PartialQuery.new collected
+ def self.partial_query(values)
+ PartialQuery.new(values)
end
class Params # :nodoc:
@@ -92,7 +91,7 @@ module ActiveRecord
def self.create(connection, block = Proc.new)
relation = block.call Params.new
bind_map = BindMap.new relation.bound_attributes
- query_builder = connection.cacheable_query relation.arel
+ query_builder = connection.cacheable_query(self, relation.arel)
new query_builder, bind_map
end
diff --git a/activerecord/lib/active_record/table_metadata.rb b/activerecord/lib/active_record/table_metadata.rb
index a1326aa359..5fe0d8b5e4 100644
--- a/activerecord/lib/active_record/table_metadata.rb
+++ b/activerecord/lib/active_record/table_metadata.rb
@@ -42,11 +42,11 @@ module ActiveRecord
end
def associated_table(table_name)
- return self if table_name == arel_table.name
-
association = klass._reflect_on_association(table_name) || klass._reflect_on_association(table_name.singularize)
- if association && !association.polymorphic?
+ if !association && table_name == arel_table.name
+ return self
+ elsif association && !association.polymorphic?
association_klass = association.klass
arel_table = association_klass.arel_table.alias(table_name)
else
diff --git a/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb b/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb
index 54c958e30b..de03550ec2 100644
--- a/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb
+++ b/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb
@@ -1,4 +1,5 @@
require 'rails/generators/active_record'
+require 'active_support/core_ext/regexp'
module ActiveRecord
module Generators # :nodoc:
diff --git a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb
index e27f16b6e4..a959f3c06a 100644
--- a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb
@@ -19,6 +19,7 @@ require 'models/professor'
require 'models/treasure'
require 'models/price_estimate'
require 'models/club'
+require 'models/user'
require 'models/member'
require 'models/membership'
require 'models/sponsor'
@@ -995,4 +996,9 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
Project.first.developers_required_by_default.create!(name: "Sean", salary: 50000)
end
end
+
+ def test_association_name_is_the_same_as_join_table_name
+ user = User.create!
+ assert_nothing_raised { user.jobs_pool.clear }
+ end
end
diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb
index 325a06d724..113131b28c 100644
--- a/activerecord/test/cases/associations/has_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_associations_test.rb
@@ -459,10 +459,6 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
assert_predicate person.references, :exists?
end
- def force_signal37_to_load_all_clients_of_firm
- companies(:first_firm).clients_of_firm.each {|f| }
- end
-
# sometimes tests on Oracle fail if ORDER BY is not provided therefore add always :order with :first
def test_counting_with_counter_sql
assert_equal 3, Firm.all.merge!(:order => "id").first.clients.count
@@ -625,6 +621,8 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
def test_find_ids_and_inverse_of
force_signal37_to_load_all_clients_of_firm
+ assert_predicate companies(:first_firm).clients_of_firm, :loaded?
+
firm = companies(:first_firm)
client = firm.clients_of_firm.find(3)
assert_kind_of Client, client
@@ -749,6 +747,9 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
def test_adding
force_signal37_to_load_all_clients_of_firm
+
+ assert_predicate companies(:first_firm).clients_of_firm, :loaded?
+
natural = Client.new("name" => "Natural Company")
companies(:first_firm).clients_of_firm << natural
assert_equal 3, companies(:first_firm).clients_of_firm.size # checking via the collection
@@ -805,6 +806,9 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
def test_adding_a_collection
force_signal37_to_load_all_clients_of_firm
+
+ assert_predicate companies(:first_firm).clients_of_firm, :loaded?
+
companies(:first_firm).clients_of_firm.concat([Client.new("name" => "Natural Company"), Client.new("name" => "Apple")])
assert_equal 4, companies(:first_firm).clients_of_firm.size
assert_equal 4, companies(:first_firm).clients_of_firm.reload.size
@@ -948,6 +952,9 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
def test_create
force_signal37_to_load_all_clients_of_firm
+
+ assert_predicate companies(:first_firm).clients_of_firm, :loaded?
+
new_client = companies(:first_firm).clients_of_firm.create("name" => "Another Client")
assert new_client.persisted?
assert_equal new_client, companies(:first_firm).clients_of_firm.last
@@ -967,6 +974,9 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
def test_deleting
force_signal37_to_load_all_clients_of_firm
+
+ assert_predicate companies(:first_firm).clients_of_firm, :loaded?
+
companies(:first_firm).clients_of_firm.delete(companies(:first_firm).clients_of_firm.first)
assert_equal 1, companies(:first_firm).clients_of_firm.size
assert_equal 1, companies(:first_firm).clients_of_firm.reload.size
@@ -1121,6 +1131,9 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
def test_deleting_a_collection
force_signal37_to_load_all_clients_of_firm
+
+ assert_predicate companies(:first_firm).clients_of_firm, :loaded?
+
companies(:first_firm).clients_of_firm.create("name" => "Another Client")
assert_equal 3, companies(:first_firm).clients_of_firm.size
companies(:first_firm).clients_of_firm.delete([companies(:first_firm).clients_of_firm[0], companies(:first_firm).clients_of_firm[1], companies(:first_firm).clients_of_firm[2]])
@@ -1130,6 +1143,9 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
def test_delete_all
force_signal37_to_load_all_clients_of_firm
+
+ assert_predicate companies(:first_firm).clients_of_firm, :loaded?
+
companies(:first_firm).dependent_clients_of_firm.create("name" => "Another Client")
clients = companies(:first_firm).dependent_clients_of_firm.to_a
assert_equal 3, clients.count
@@ -1141,6 +1157,9 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
def test_delete_all_with_not_yet_loaded_association_collection
force_signal37_to_load_all_clients_of_firm
+
+ assert_predicate companies(:first_firm).clients_of_firm, :loaded?
+
companies(:first_firm).clients_of_firm.create("name" => "Another Client")
assert_equal 3, companies(:first_firm).clients_of_firm.size
companies(:first_firm).clients_of_firm.reset
@@ -1329,6 +1348,9 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
def test_deleting_a_item_which_is_not_in_the_collection
force_signal37_to_load_all_clients_of_firm
+
+ assert_predicate companies(:first_firm).clients_of_firm, :loaded?
+
summit = Client.find_by_name('Summit')
companies(:first_firm).clients_of_firm.delete(summit)
assert_equal 2, companies(:first_firm).clients_of_firm.size
@@ -1365,6 +1387,8 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
def test_destroying
force_signal37_to_load_all_clients_of_firm
+ assert_predicate companies(:first_firm).clients_of_firm, :loaded?
+
assert_difference "Client.count", -1 do
companies(:first_firm).clients_of_firm.destroy(companies(:first_firm).clients_of_firm.first)
end
@@ -1376,6 +1400,8 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
def test_destroying_by_integer_id
force_signal37_to_load_all_clients_of_firm
+ assert_predicate companies(:first_firm).clients_of_firm, :loaded?
+
assert_difference "Client.count", -1 do
companies(:first_firm).clients_of_firm.destroy(companies(:first_firm).clients_of_firm.first.id)
end
@@ -1387,6 +1413,8 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
def test_destroying_by_string_id
force_signal37_to_load_all_clients_of_firm
+ assert_predicate companies(:first_firm).clients_of_firm, :loaded?
+
assert_difference "Client.count", -1 do
companies(:first_firm).clients_of_firm.destroy(companies(:first_firm).clients_of_firm.first.id.to_s)
end
@@ -1397,6 +1425,9 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
def test_destroying_a_collection
force_signal37_to_load_all_clients_of_firm
+
+ assert_predicate companies(:first_firm).clients_of_firm, :loaded?
+
companies(:first_firm).clients_of_firm.create("name" => "Another Client")
assert_equal 3, companies(:first_firm).clients_of_firm.size
@@ -1410,6 +1441,9 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
def test_destroy_all
force_signal37_to_load_all_clients_of_firm
+
+ assert_predicate companies(:first_firm).clients_of_firm, :loaded?
+
clients = companies(:first_firm).clients_of_firm.to_a
assert !clients.empty?, "37signals has clients after load"
destroyed = companies(:first_firm).clients_of_firm.destroy_all
@@ -2428,4 +2462,10 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
assert_equal [bulb.id], car.bulb_ids
assert_no_queries { car.bulb_ids }
end
+
+ private
+
+ def force_signal37_to_load_all_clients_of_firm
+ companies(:first_firm).clients_of_firm.load_target
+ end
end
diff --git a/activerecord/test/cases/associations/left_outer_join_association_test.rb b/activerecord/test/cases/associations/left_outer_join_association_test.rb
index fcf1e0b040..e3b257efb2 100644
--- a/activerecord/test/cases/associations/left_outer_join_association_test.rb
+++ b/activerecord/test/cases/associations/left_outer_join_association_test.rb
@@ -5,6 +5,7 @@ require 'models/author'
require 'models/essay'
require 'models/categorization'
require 'models/person'
+require 'active_support/core_ext/regexp'
class LeftOuterJoinAssociationTest < ActiveRecord::TestCase
fixtures :authors, :essays, :posts, :comments, :categorizations, :people
diff --git a/activerecord/test/cases/associations_test.rb b/activerecord/test/cases/associations_test.rb
index 7412d48fe8..7efacb44f3 100644
--- a/activerecord/test/cases/associations_test.rb
+++ b/activerecord/test/cases/associations_test.rb
@@ -45,7 +45,6 @@ class AssociationsTest < ActiveRecord::TestCase
ship = Ship.create!(:name => "The good ship Dollypop")
part = ship.parts.create!(:name => "Mast")
part.mark_for_destruction
- ship.parts.send(:load_target)
assert ship.parts[0].marked_for_destruction?
end
@@ -54,7 +53,6 @@ class AssociationsTest < ActiveRecord::TestCase
part = ship.parts.create!(:name => "Mast")
part.mark_for_destruction
ShipPart.find(part.id).update_columns(name: 'Deck')
- ship.parts.send(:load_target)
assert_equal 'Deck', ship.parts[0].name
end
@@ -183,6 +181,14 @@ class AssociationProxyTest < ActiveRecord::TestCase
assert !david.projects.loaded?
end
+ def test_load_does_load_target
+ david = developers(:david)
+
+ assert !david.projects.loaded?
+ david.projects.load
+ assert david.projects.loaded?
+ end
+
def test_inspect_does_not_reload_a_not_yet_loaded_target
andreas = Developer.new :name => 'Andreas', :log => 'new developer added'
assert !andreas.audit_logs.loaded?
diff --git a/activerecord/test/cases/attributes_test.rb b/activerecord/test/cases/attributes_test.rb
index 7bcaa53aa2..604411da97 100644
--- a/activerecord/test/cases/attributes_test.rb
+++ b/activerecord/test/cases/attributes_test.rb
@@ -205,5 +205,49 @@ module ActiveRecord
assert_equal(:bar, child.new(foo: :bar).foo)
end
+
+ test "attributes not backed by database columns are not dirty when unchanged" do
+ refute OverloadedType.new.non_existent_decimal_changed?
+ end
+
+ test "attributes not backed by database columns are always initialized" do
+ OverloadedType.create!
+ model = OverloadedType.first
+
+ assert_nil model.non_existent_decimal
+ model.non_existent_decimal = "123"
+ assert_equal 123, model.non_existent_decimal
+ end
+
+ test "attributes not backed by database columns return the default on models loaded from database" do
+ child = Class.new(OverloadedType) do
+ attribute :non_existent_decimal, :decimal, default: 123
+ end
+ child.create!
+ model = child.first
+
+ assert_equal 123, model.non_existent_decimal
+ end
+
+ test "attributes not backed by database columns properly interact with mutation and dirty" do
+ child = Class.new(ActiveRecord::Base) do
+ self.table_name = "topics"
+ attribute :foo, :string, default: "lol"
+ end
+ child.create!
+ model = child.first
+
+ assert_equal "lol", model.foo
+
+ model.foo << "asdf"
+ assert_equal "lolasdf", model.foo
+ assert model.foo_changed?
+
+ model.reload
+ assert_equal "lol", model.foo
+
+ model.foo = "lol"
+ refute model.changed?
+ end
end
end
diff --git a/activerecord/test/cases/nested_attributes_test.rb b/activerecord/test/cases/nested_attributes_test.rb
index 11fb164d50..8a08056bbe 100644
--- a/activerecord/test/cases/nested_attributes_test.rb
+++ b/activerecord/test/cases/nested_attributes_test.rb
@@ -642,13 +642,13 @@ module NestedAttributesOnACollectionAssociationTests
def test_should_not_overwrite_unsaved_updates_when_loading_association
@pirate.reload
@pirate.send(association_setter, [{ :id => @child_1.id, :name => 'Grace OMalley' }])
- assert_equal 'Grace OMalley', @pirate.send(@association_name).send(:load_target).find { |r| r.id == @child_1.id }.name
+ assert_equal 'Grace OMalley', @pirate.send(@association_name).load_target.find { |r| r.id == @child_1.id }.name
end
def test_should_preserve_order_when_not_overwriting_unsaved_updates
@pirate.reload
@pirate.send(association_setter, [{ :id => @child_1.id, :name => 'Grace OMalley' }])
- assert_equal @child_1.id, @pirate.send(@association_name).send(:load_target).first.id
+ assert_equal @child_1.id, @pirate.send(@association_name).load_target.first.id
end
def test_should_refresh_saved_records_when_not_overwriting_unsaved_updates
@@ -657,13 +657,13 @@ module NestedAttributesOnACollectionAssociationTests
@pirate.send(@association_name) << record
record.save!
@pirate.send(@association_name).last.update!(name: 'Polly')
- assert_equal 'Polly', @pirate.send(@association_name).send(:load_target).last.name
+ assert_equal 'Polly', @pirate.send(@association_name).load_target.last.name
end
def test_should_not_remove_scheduled_destroys_when_loading_association
@pirate.reload
@pirate.send(association_setter, [{ :id => @child_1.id, :_destroy => '1' }])
- assert @pirate.send(@association_name).send(:load_target).find { |r| r.id == @child_1.id }.marked_for_destruction?
+ assert @pirate.send(@association_name).load_target.find { |r| r.id == @child_1.id }.marked_for_destruction?
end
def test_should_take_a_hash_with_composite_id_keys_and_assign_the_attributes_to_the_associated_models
diff --git a/activerecord/test/cases/quoting_test.rb b/activerecord/test/cases/quoting_test.rb
index c01c82f4f5..225e23bc83 100644
--- a/activerecord/test/cases/quoting_test.rb
+++ b/activerecord/test/cases/quoting_test.rb
@@ -149,5 +149,21 @@ module ActiveRecord
assert_equal "1800", @quoter.quote(30.minutes)
end
end
+
+ class QuoteBooleanTest < ActiveRecord::TestCase
+ def setup
+ @connection = ActiveRecord::Base.connection
+ end
+
+ def test_quote_returns_frozen_string
+ assert_predicate @connection.quote(true), :frozen?
+ assert_predicate @connection.quote(false), :frozen?
+ end
+
+ def test_type_cast_returns_frozen_value
+ assert_predicate @connection.type_cast(true), :frozen?
+ assert_predicate @connection.type_cast(false), :frozen?
+ end
+ end
end
end
diff --git a/activerecord/test/cases/scoping/default_scoping_test.rb b/activerecord/test/cases/scoping/default_scoping_test.rb
index 30d342ac70..6679f9415b 100644
--- a/activerecord/test/cases/scoping/default_scoping_test.rb
+++ b/activerecord/test/cases/scoping/default_scoping_test.rb
@@ -5,6 +5,7 @@ require 'models/developer'
require 'models/computer'
require 'models/vehicle'
require 'models/cat'
+require 'active_support/core_ext/regexp'
class DefaultScopingTest < ActiveRecord::TestCase
fixtures :developers, :posts, :comments
diff --git a/activerecord/test/cases/scoping/relation_scoping_test.rb b/activerecord/test/cases/scoping/relation_scoping_test.rb
index c15d57460b..ef46fd5d9a 100644
--- a/activerecord/test/cases/scoping/relation_scoping_test.rb
+++ b/activerecord/test/cases/scoping/relation_scoping_test.rb
@@ -228,6 +228,13 @@ class RelationScopingTest < ActiveRecord::TestCase
assert SpecialComment.all.any?
end
end
+
+ def test_circular_joins_with_current_scope_does_not_crash
+ posts = Post.joins(comments: :post).scoping do
+ Post.current_scope.first(10)
+ end
+ assert_equal posts, Post.joins(comments: :post).first(10)
+ end
end
class NestedRelationScopingTest < ActiveRecord::TestCase
diff --git a/activerecord/test/cases/test_case.rb b/activerecord/test/cases/test_case.rb
index cde5488315..fcb6552e5b 100644
--- a/activerecord/test/cases/test_case.rb
+++ b/activerecord/test/cases/test_case.rb
@@ -1,5 +1,6 @@
require 'active_support/test_case'
require 'active_support/testing/stream'
+require 'active_support/core_ext/regexp'
module ActiveRecord
# = Active Record Test Case
diff --git a/activerecord/test/models/user.rb b/activerecord/test/models/user.rb
index f5dc93e994..97107a35a0 100644
--- a/activerecord/test/models/user.rb
+++ b/activerecord/test/models/user.rb
@@ -1,6 +1,12 @@
+require 'models/job'
+
class User < ActiveRecord::Base
has_secure_token
has_secure_token :auth_token
+
+ has_and_belongs_to_many :jobs_pool,
+ class_name: Job,
+ join_table: 'jobs_pool'
end
class UserWithNotification < User
diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb
index 2f2993ce18..a5155e9cdb 100644
--- a/activerecord/test/schema/schema.rb
+++ b/activerecord/test/schema/schema.rb
@@ -390,6 +390,11 @@ ActiveRecord::Schema.define do
t.integer :ideal_reference_id
end
+ create_table :jobs_pool, force: true, id: false do |t|
+ t.references :job, null: false, index: true
+ t.references :user, null: false, index: true
+ end
+
create_table :keyboards, force: true, id: false do |t|
t.primary_key :key_number
t.string :name
diff --git a/activesupport/lib/active_support/message_encryptor.rb b/activesupport/lib/active_support/message_encryptor.rb
index 87efe117c5..1f2736388d 100644
--- a/activesupport/lib/active_support/message_encryptor.rb
+++ b/activesupport/lib/active_support/message_encryptor.rb
@@ -99,6 +99,10 @@ module ActiveSupport
def _decrypt(encrypted_message)
cipher = new_cipher
encrypted_data, iv, auth_tag = encrypted_message.split("--".freeze).map {|v| ::Base64.strict_decode64(v)}
+
+ # Currently the OpenSSL bindings do not raise an error if auth_tag is
+ # truncated, which would allow an attacker to easily forge it. See
+ # https://github.com/ruby/openssl/issues/63
raise InvalidMessage if aead_mode? && auth_tag.bytes.length != 16
cipher.decrypt
diff --git a/guides/source/active_record_querying.md b/guides/source/active_record_querying.md
index 90f200133b..8ffd0d033d 100644
--- a/guides/source/active_record_querying.md
+++ b/guides/source/active_record_querying.md
@@ -601,6 +601,7 @@ If you want to call `order` multiple times, subsequent orders will be appended t
Client.order("orders_count ASC").order("created_at DESC")
# SELECT * FROM clients ORDER BY orders_count ASC, created_at DESC
```
+WARNING: If you are using **MySQL 5.7.5** and above, then on selecting fields from a result set using methods like `select`, `pluck` and `ids`; the `order` method will raise an `ActiveRecord::StatementInvalid` exception unless the field(s) used in `order` clause are included in the select list. See the next section for selecting fields from the result set.
Selecting Specific Fields
-------------------------
diff --git a/guides/source/getting_started.md b/guides/source/getting_started.md
index 0f1c3735e8..73dbb2bc40 100644
--- a/guides/source/getting_started.md
+++ b/guides/source/getting_started.md
@@ -465,29 +465,24 @@ The first part identifies which template is missing. In this case, it's the
then it will attempt to load a template called `application/new`. It looks for
one here because the `ArticlesController` inherits from `ApplicationController`.
-The next part of the message contains a hash. The `:locale` key in this hash
-simply indicates which spoken language template should be retrieved. By default,
-this is the English - or "en" - template. The next key, `:formats` specifies the
-format of the template to be served in response. The default format is `:html`, and
-so Rails is looking for an HTML template. The final key, `:handlers`, is telling
-us what _template handlers_ could be used to render our template. `:erb` is most
-commonly used for HTML templates, `:builder` is used for XML templates, and
-`:coffee` uses CoffeeScript to build JavaScript templates.
-
-The message also contains `request.formats` which specifies the format of template to be
-served in response. It is set to `text/html` as we requested this page via browser, so Rails
-is looking for an HTML template.
+The next part of the message contains `request.formats` which specifies
+the format of template to be served in response. It is set to `text/html` as we
+requested this page via browser, so Rails is looking for an HTML template.
+`request.variants` specifies what kind of physical devices would be served by
+the response and helps Rails determine which template to use in the response.
+It is empty because no information has been provided.
The simplest template that would work in this case would be one located at
`app/views/articles/new.html.erb`. The extension of this file name is important:
the first extension is the _format_ of the template, and the second extension
-is the _handler_ that will be used. Rails is attempting to find a template
-called `articles/new` within `app/views` for the application. The format for
-this template can only be `html` and the handler must be one of `erb`,
-`builder` or `coffee`. `:erb` is most commonly used for HTML templates, `:builder` is
-used for XML templates, and `:coffee` uses CoffeeScript to build JavaScript templates.
-Because you want to create a new HTML form, you will be
-using the `ERB` language which is designed to embed Ruby in HTML.
+is the _handler_ that will be used to render the template. Rails is attempting
+to find a template called `articles/new` within `app/views` for the
+application. The format for this template can only be `html` and the default
+handler for HTML is `erb`. Rails uses other handlers for other formats.
+`builder` handler is used to build XML templates and `coffee` handler uses
+CoffeeScript to build JavaScript templates. Because you want to create a new
+HTML form, you will be using the `ERB` language which is designed to embed Ruby
+in HTML.
Therefore the file should be called `articles/new.html.erb` and needs to be
located inside the `app/views` directory of the application.
diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md
index 1694abb61a..70f4b84237 100644
--- a/railties/CHANGELOG.md
+++ b/railties/CHANGELOG.md
@@ -1,3 +1,7 @@
+* A generated app should not include Uglifier with `--skip-javascript` option.
+
+ *Ben Pickles*
+
* Set session store to cookie store internally and remove the initializer from
the generated app.
diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb
index af3c6dead3..8d4056c202 100644
--- a/railties/lib/rails/generators/app_base.rb
+++ b/railties/lib/rails/generators/app_base.rb
@@ -299,9 +299,11 @@ module Rails
gems << GemfileEntry.github('sass-rails', 'rails/sass-rails', nil,
'Use SCSS for stylesheets')
- gems << GemfileEntry.version('uglifier',
- '>= 1.3.0',
- 'Use Uglifier as compressor for JavaScript assets')
+ if !options[:skip_javascript]
+ gems << GemfileEntry.version('uglifier',
+ '>= 1.3.0',
+ 'Use Uglifier as compressor for JavaScript assets')
+ end
gems
end
diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt
index 363af05459..7deab5dbb1 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt
+++ b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt
@@ -19,8 +19,12 @@ Rails.application.configure do
config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?
<%- unless options.skip_sprockets? -%>
+ <%- if options.skip_javascript? -%>
+ # Compress CSS.
+ <%- else -%>
# Compress JavaScripts and CSS.
config.assets.js_compressor = :uglifier
+ <%- end -%>
# config.assets.css_compressor = :sass
# Do not fallback to assets pipeline if a precompiled asset is missed.
diff --git a/railties/test/application/integration_test_case_test.rb b/railties/test/application/integration_test_case_test.rb
index 52df5a2e5a..68e2de80c4 100644
--- a/railties/test/application/integration_test_case_test.rb
+++ b/railties/test/application/integration_test_case_test.rb
@@ -42,4 +42,32 @@ module ApplicationTests
assert_match(/0 failures, 0 errors/, output)
end
end
+
+ class IntegrationTestDefaultApp < ActiveSupport::TestCase
+ include ActiveSupport::Testing::Isolation
+
+ setup do
+ build_app
+ end
+
+ teardown do
+ teardown_app
+ end
+
+ test "app method of integration tests returns test_app by default" do
+ app_file 'test/integration/default_app_test.rb', <<-RUBY
+ require 'test_helper'
+
+ class DefaultAppIntegrationTest < ActionDispatch::IntegrationTest
+ def test_app_returns_action_dispatch_test_app_by_default
+ assert_equal ActionDispatch.test_app, app
+ end
+ end
+ RUBY
+
+ output = Dir.chdir(app_path) { `bin/rails test 2>&1` }
+ assert_equal 0, $?.to_i, output
+ assert_match(/0 failures, 0 errors/, output)
+ end
+ end
end
diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb
index b968f9f207..09309b5cd0 100644
--- a/railties/test/generators/app_generator_test.rb
+++ b/railties/test/generators/app_generator_test.rb
@@ -468,6 +468,11 @@ class AppGeneratorTest < Rails::Generators::TestCase
assert_file "Gemfile" do |content|
assert_no_match(/coffee-rails/, content)
assert_no_match(/jquery-rails/, content)
+ assert_no_match(/uglifier/, content)
+ end
+
+ assert_file "config/environments/production.rb" do |content|
+ assert_no_match(/config\.assets\.js_compressor = :uglifier/, content)
end
end