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/routing/mapper.rb9
-rw-r--r--actionpack/test/dispatch/routing_test.rb18
-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--activerecord/CHANGELOG.md4
-rw-r--r--activerecord/lib/active_record/associations/collection_proxy.rb8
-rw-r--r--activerecord/lib/active_record/associations/join_dependency/join_association.rb4
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb9
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/quoting.rb4
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_adapter.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb17
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql/quoting.rb4
-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/sqlite3/quoting.rb2
-rw-r--r--activerecord/lib/active_record/relation/finder_methods.rb8
-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/test/cases/associations/has_and_belongs_to_many_associations_test.rb6
-rw-r--r--activerecord/test/cases/associations_test.rb10
-rw-r--r--activerecord/test/cases/scoping/relation_scoping_test.rb7
-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
33 files changed, 179 insertions, 79 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 10bc8b1898..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.1.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/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/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/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/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index d3e1cf68a2..14a6c3c9f7 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,7 @@
+* 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
diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb
index db3037d8f9..806a905323 100644
--- a/activerecord/lib/active_record/associations/collection_proxy.rb
+++ b/activerecord/lib/active_record/associations/collection_proxy.rb
@@ -29,7 +29,7 @@ module ActiveRecord
# instantiation of the actual post records.
class CollectionProxy < Relation
delegate(*(ActiveRecord::Calculations.public_instance_methods - [:count]), to: :scope)
- delegate :find_nth, :exists?, :update_all, :arel, to: :scope
+ delegate :exists?, :update_all, :arel, to: :scope
def initialize(klass, association) #:nodoc:
@association = association
@@ -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/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/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 0a58921549..eda6af08e3 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
@@ -150,10 +150,6 @@ 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)
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 25e3939b62..610d78245f 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
@@ -410,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
@@ -544,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
@@ -553,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/quoting.rb b/activerecord/lib/active_record/connection_adapters/mysql/quoting.rb
index 5b59e39d9f..af1db30047 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql/quoting.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql/quoting.rb
@@ -5,11 +5,11 @@ module ActiveRecord
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/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/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb
index d255cad91b..916dca33bd 100644
--- a/activerecord/lib/active_record/relation/finder_methods.rb
+++ b/activerecord/lib/active_record/relation/finder_methods.rb
@@ -514,7 +514,7 @@ module ActiveRecord
def find_take
if loaded?
- @records.first
+ records.first
else
@take ||= limit(1).records.first
end
@@ -531,7 +531,7 @@ module ActiveRecord
MSG
end
if loaded?
- @records[index]
+ records[index]
else
offset ||= offset_index
@offsets[offset + index] ||= find_nth_with_limit_and_offset(index, 1, offset: offset).first
@@ -557,7 +557,7 @@ module ActiveRecord
def find_nth_from_last(index)
if loaded?
- @records[-index]
+ records[-index]
else
relation = if order_values.empty? && primary_key
order(arel_attribute(primary_key).asc)
@@ -578,7 +578,7 @@ module ActiveRecord
def find_nth_with_limit_and_offset(index, limit, offset:) # :nodoc:
if loaded?
- @records[index, limit]
+ records[index, limit]
else
index += offset
find_nth_with_limit(index, limit)
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/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_test.rb b/activerecord/test/cases/associations_test.rb
index 5fb7f191ed..7efacb44f3 100644
--- a/activerecord/test/cases/associations_test.rb
+++ b/activerecord/test/cases/associations_test.rb
@@ -181,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?
@@ -246,6 +254,8 @@ class AssociationProxyTest < ActiveRecord::TestCase
test "first! works on loaded associations" do
david = authors(:david)
assert_equal david.posts.first, david.posts.reload.first!
+ assert david.posts.loaded?
+ assert_no_queries { david.posts.first! }
end
def test_reset_unloads_target
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/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.