aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionpack/lib/action_dispatch/http/request.rb8
-rw-r--r--activerecord/CHANGELOG.md10
-rw-r--r--activerecord/lib/active_record/associations.rb3
-rw-r--r--activerecord/lib/active_record/base.rb1
-rw-r--r--activerecord/lib/active_record/relation.rb3
-rw-r--r--activerecord/lib/active_record/relation/query_methods.rb4
-rw-r--r--activerecord/test/cases/associations/eager_test.rb2
-rw-r--r--activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb25
-rw-r--r--activerecord/test/cases/associations/has_many_through_associations_test.rb2
-rw-r--r--activerecord/test/cases/associations/join_model_test.rb8
-rw-r--r--activerecord/test/cases/base_test.rb10
-rw-r--r--activerecord/test/cases/calculations_test.rb9
-rw-r--r--activerecord/test/cases/relation/mutation_test.rb17
-rw-r--r--activerecord/test/cases/relations_test.rb11
-rw-r--r--activesupport/CHANGELOG.md22
-rw-r--r--activesupport/lib/active_support/core_ext/class.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/class/delegating_attributes.rb45
-rw-r--r--activesupport/lib/active_support/multibyte/chars.rb2
-rw-r--r--activesupport/lib/active_support/ordered_options.rb8
-rw-r--r--activesupport/test/core_ext/class/delegating_attributes_test.rb122
-rw-r--r--activesupport/test/ordered_options_test.rb15
-rw-r--r--guides/source/action_mailer_basics.md2
-rw-r--r--guides/source/upgrading_ruby_on_rails.md2
23 files changed, 125 insertions, 207 deletions
diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb
index 0f5c5a8eb1..836bdead25 100644
--- a/actionpack/lib/action_dispatch/http/request.rb
+++ b/actionpack/lib/action_dispatch/http/request.rb
@@ -235,11 +235,13 @@ module ActionDispatch
end
alias :xhr? :xml_http_request?
+ # Returns the IP address of client as a +String+.
def ip
@ip ||= super
end
- # Originating IP address, usually set by the RemoteIp middleware.
+ # Returns the IP address of client as a +String+,
+ # usually set by the RemoteIp middleware.
def remote_ip
@remote_ip ||= (@env["action_dispatch.remote_ip"] || ip).to_s
end
@@ -256,13 +258,13 @@ module ActionDispatch
env[ACTION_DISPATCH_REQUEST_ID]
end
- def request_id=(id)
+ def request_id=(id) # :nodoc:
env[ACTION_DISPATCH_REQUEST_ID] = id
end
alias_method :uuid, :request_id
- def x_request_id
+ def x_request_id # :nodoc
@env[HTTP_X_REQUEST_ID]
end
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index 5b09101bca..e90490f8b6 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,13 @@
+* Pass `:extend` option for `has_and_belongs_to_many` associations to the underlying `has_many :through`.
+
+ *Jaehyun Shin*
+
+* Deprecate `Relation#uniq` use `Relation#distinct` instead.
+
+ See #9683.
+
+ *Yves Senn*
+
* Allow single table inheritance instantiation to work when storing
demodulized class names.
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb
index a3c30642d0..1ca648d48d 100644
--- a/activerecord/lib/active_record/associations.rb
+++ b/activerecord/lib/active_record/associations.rb
@@ -266,7 +266,6 @@ module ActiveRecord
# others.find(*args) | X | X | X
# others.exists? | X | X | X
# others.distinct | X | X | X
- # others.uniq | X | X | X
# others.reset | X | X | X
#
# === Overriding generated methods
@@ -1738,7 +1737,7 @@ module ActiveRecord
hm_options[:through] = middle_reflection.name
hm_options[:source] = join_model.right_reflection.name
- [:before_add, :after_add, :before_remove, :after_remove, :autosave, :validate, :join_table, :class_name].each do |k|
+ [:before_add, :after_add, :before_remove, :after_remove, :autosave, :validate, :join_table, :class_name, :extend].each do |k|
hm_options[k] = options[k] if options.key? k
end
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index 9c5b7d937d..c918e88590 100644
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -5,7 +5,6 @@ require 'active_support/dependencies'
require 'active_support/descendants_tracker'
require 'active_support/time'
require 'active_support/core_ext/module/attribute_accessors'
-require 'active_support/core_ext/class/delegating_attributes'
require 'active_support/core_ext/array/extract_options'
require 'active_support/core_ext/hash/deep_merge'
require 'active_support/core_ext/hash/slice'
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index 85648a7f8f..7d37313058 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -9,7 +9,7 @@ module ActiveRecord
:extending, :unscope]
SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :reordering,
- :reverse_order, :distinct, :create_with, :uniq]
+ :reverse_order, :distinct, :create_with]
CLAUSE_METHODS = [:where, :having, :from]
INVALID_METHODS_FOR_DELETE_ALL = [:limit, :distinct, :offset, :group, :having]
@@ -618,6 +618,7 @@ module ActiveRecord
def uniq_value
distinct_value
end
+ deprecate uniq_value: :distinct_value
# Compares two relations for equality.
def ==(other)
diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb
index 69ce5cdc2a..fd78db2e95 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -587,7 +587,7 @@ module ActiveRecord
#
# The two relations must be structurally compatible: they must be scoping the same model, and
# they must differ only by +where+ (if no +group+ has been defined) or +having+ (if a +group+ is
- # present). Neither relation may have a +limit+, +offset+, or +uniq+ set.
+ # present). Neither relation may have a +limit+, +offset+, or +distinct+ set.
#
# Post.where("id = 1").or(Post.where("id = 2"))
# # SELECT `posts`.* FROM `posts` WHERE (('id = 1' OR 'id = 2'))
@@ -790,6 +790,7 @@ module ActiveRecord
spawn.distinct!(value)
end
alias uniq distinct
+ deprecate uniq: :distinct
# Like #distinct, but modifies relation in place.
def distinct!(value = true) # :nodoc:
@@ -797,6 +798,7 @@ module ActiveRecord
self
end
alias uniq! distinct!
+ deprecate uniq!: :distinct!
# Used to extend a scope with additional methods, either through
# a module or through a block provided.
diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb
index 0ecf2ddfd1..ffbf60e390 100644
--- a/activerecord/test/cases/associations/eager_test.rb
+++ b/activerecord/test/cases/associations/eager_test.rb
@@ -1167,7 +1167,7 @@ class EagerAssociationTest < ActiveRecord::TestCase
assert_no_queries { assert client.accounts.empty? }
end
- def test_preloading_has_many_through_with_uniq
+ def test_preloading_has_many_through_with_distinct
mary = Author.includes(:unique_categorized_posts).where(:id => authors(:mary).id).first
assert_equal 1, mary.unique_categorized_posts.length
assert_equal 1, mary.unique_categorized_post_ids.length
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 aea9207bfe..e584c94ad8 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
@@ -83,6 +83,16 @@ class DeveloperWithSymbolClassName < Developer
has_and_belongs_to_many :projects, class_name: :ProjectWithSymbolsForKeys
end
+class DeveloperWithExtendOption < Developer
+ module NamedExtension
+ def category
+ 'sns'
+ end
+ end
+
+ has_and_belongs_to_many :projects, extend: NamedExtension
+end
+
class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
fixtures :accounts, :companies, :categories, :posts, :categories_posts, :developers, :projects, :developers_projects,
:parrots, :pirates, :parrots_pirates, :treasures, :price_estimates, :tags, :taggings, :computers
@@ -234,7 +244,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
assert_equal developers, new_project.developers
end
- def test_habtm_unique_order_preserved
+ def test_habtm_distinct_order_preserved
assert_equal developers(:poor_jamis, :jamis, :david), projects(:active_record).non_unique_developers
assert_equal developers(:poor_jamis, :jamis, :david), projects(:active_record).developers
end
@@ -339,7 +349,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
assert_equal 'Yet Another Testing Title', another_post.title
end
- def test_uniq_after_the_fact
+ def test_distinct_after_the_fact
dev = developers(:jamis)
dev.projects << projects(:active_record)
dev.projects << projects(:active_record)
@@ -348,13 +358,13 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
assert_equal 1, dev.projects.distinct.size
end
- def test_uniq_before_the_fact
+ def test_distinct_before_the_fact
projects(:active_record).developers << developers(:jamis)
projects(:active_record).developers << developers(:david)
assert_equal 3, projects(:active_record, :reload).developers.size
end
- def test_uniq_option_prevents_duplicate_push
+ def test_distinct_option_prevents_duplicate_push
project = projects(:active_record)
project.developers << developers(:jamis)
project.developers << developers(:david)
@@ -365,7 +375,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
assert_equal 3, project.developers.size
end
- def test_uniq_when_association_already_loaded
+ def test_distinct_when_association_already_loaded
project = projects(:active_record)
project.developers << [ developers(:jamis), developers(:david), developers(:jamis), developers(:david) ]
assert_equal 3, Project.includes(:developers).find(project.id).developers.size
@@ -577,6 +587,11 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
assert_equal developers(:poor_jamis), projects(:active_record).developers.where("salary < 10000").first
end
+ def test_association_with_extend_option
+ eponine = DeveloperWithExtendOption.create(name: 'Eponine')
+ assert_equal 'sns', eponine.projects.category
+ end
+
def test_replace_with_less
david = developers(:david)
david.projects = [projects(:action_controller)]
diff --git a/activerecord/test/cases/associations/has_many_through_associations_test.rb b/activerecord/test/cases/associations/has_many_through_associations_test.rb
index 190cef55c4..1d545af5a5 100644
--- a/activerecord/test/cases/associations/has_many_through_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb
@@ -960,7 +960,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
assert_equal 1, category.categorizations.where(:special => true).count
end
- def test_joining_has_many_through_with_uniq
+ def test_joining_has_many_through_with_distinct
mary = Author.joins(:unique_categorized_posts).where(:id => authors(:mary).id).first
assert_equal 1, mary.unique_categorized_posts.length
assert_equal 1, mary.unique_categorized_post_ids.length
diff --git a/activerecord/test/cases/associations/join_model_test.rb b/activerecord/test/cases/associations/join_model_test.rb
index 213be50e67..5575419c35 100644
--- a/activerecord/test/cases/associations/join_model_test.rb
+++ b/activerecord/test/cases/associations/join_model_test.rb
@@ -35,12 +35,12 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase
assert categories(:sti_test).authors.include?(authors(:mary))
end
- def test_has_many_uniq_through_join_model
+ def test_has_many_distinct_through_join_model
assert_equal 2, authors(:mary).categorized_posts.size
assert_equal 1, authors(:mary).unique_categorized_posts.size
end
- def test_has_many_uniq_through_count
+ def test_has_many_distinct_through_count
author = authors(:mary)
assert !authors(:mary).unique_categorized_posts.loaded?
assert_queries(1) { assert_equal 1, author.unique_categorized_posts.count }
@@ -49,7 +49,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase
assert !authors(:mary).unique_categorized_posts.loaded?
end
- def test_has_many_uniq_through_find
+ def test_has_many_distinct_through_find
assert_equal 1, authors(:mary).unique_categorized_posts.to_a.size
end
@@ -625,7 +625,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase
assert_equal [comments(:does_it_hurt)], authors(:david).special_post_comments
end
- def test_uniq_has_many_through_should_retain_order
+ def test_distinct_has_many_through_should_retain_order
comment_ids = authors(:david).comments.map(&:id)
assert_equal comment_ids.sort, authors(:david).ordered_uniq_comments.map(&:id)
assert_equal comment_ids.sort.reverse, authors(:david).ordered_uniq_comments_desc.map(&:id)
diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb
index 4306738670..31c31e4329 100644
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -1411,15 +1411,13 @@ class BasicsTest < ActiveRecord::TestCase
end
def test_uniq_delegates_to_scoped
- scope = stub
- Bird.stubs(:all).returns(mock(:uniq => scope))
- assert_equal scope, Bird.uniq
+ assert_deprecated do
+ assert_equal Bird.all.distinct, Bird.uniq
+ end
end
def test_distinct_delegates_to_scoped
- scope = stub
- Bird.stubs(:all).returns(mock(:distinct => scope))
- assert_equal scope, Bird.distinct
+ assert_equal Bird.all.distinct, Bird.distinct
end
def test_table_name_with_2_abstract_subclasses
diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb
index 8fc996ee74..b246eae5f5 100644
--- a/activerecord/test/cases/calculations_test.rb
+++ b/activerecord/test/cases/calculations_test.rb
@@ -359,7 +359,10 @@ class CalculationsTest < ActiveRecord::TestCase
def test_count_with_distinct
assert_equal 4, Account.select(:credit_limit).distinct.count
- assert_equal 4, Account.select(:credit_limit).uniq.count
+
+ assert_deprecated do
+ assert_equal 4, Account.select(:credit_limit).uniq.count
+ end
end
def test_count_with_aliased_attribute
@@ -504,8 +507,8 @@ class CalculationsTest < ActiveRecord::TestCase
assert_equal [ topic.written_on ], relation.pluck(:written_on)
end
- def test_pluck_and_uniq
- assert_equal [50, 53, 55, 60], Account.order(:credit_limit).uniq.pluck(:credit_limit)
+ def test_pluck_and_distinct
+ assert_equal [50, 53, 55, 60], Account.order(:credit_limit).distinct.pluck(:credit_limit)
end
def test_pluck_in_relation
diff --git a/activerecord/test/cases/relation/mutation_test.rb b/activerecord/test/cases/relation/mutation_test.rb
index 45ead08bd5..ba4d9d2503 100644
--- a/activerecord/test/cases/relation/mutation_test.rb
+++ b/activerecord/test/cases/relation/mutation_test.rb
@@ -81,7 +81,7 @@ module ActiveRecord
assert_equal [], relation.extending_values
end
- (Relation::SINGLE_VALUE_METHODS - [:lock, :reordering, :reverse_order, :create_with]).each do |method|
+ (Relation::SINGLE_VALUE_METHODS - [:lock, :reordering, :reverse_order, :create_with, :uniq]).each do |method|
test "##{method}!" do
assert relation.public_send("#{method}!", :foo).equal?(relation)
assert_equal :foo, relation.public_send("#{method}_value")
@@ -153,13 +153,22 @@ module ActiveRecord
test 'distinct!' do
relation.distinct! :foo
assert_equal :foo, relation.distinct_value
- assert_equal :foo, relation.uniq_value # deprecated access
+
+ assert_deprecated do
+ assert_equal :foo, relation.uniq_value # deprecated access
+ end
end
test 'uniq! was replaced by distinct!' do
- relation.uniq! :foo
+ assert_deprecated(/use distinct! instead/) do
+ relation.uniq! :foo
+ end
+
+ assert_deprecated(/use distinct_value instead/) do
+ assert_equal :foo, relation.uniq_value # deprecated access
+ end
+
assert_equal :foo, relation.distinct_value
- assert_equal :foo, relation.uniq_value # deprecated access
end
end
end
diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb
index b8e2041b6d..a4ca3ab637 100644
--- a/activerecord/test/cases/relations_test.rb
+++ b/activerecord/test/cases/relations_test.rb
@@ -908,7 +908,7 @@ class RelationTest < ActiveRecord::TestCase
def test_delete_all_with_unpermitted_relation_raises_error
assert_raises(ActiveRecord::ActiveRecordError) { Author.limit(10).delete_all }
- assert_raises(ActiveRecord::ActiveRecordError) { Author.uniq.delete_all }
+ assert_raises(ActiveRecord::ActiveRecordError) { Author.distinct.delete_all }
assert_raises(ActiveRecord::ActiveRecordError) { Author.group(:name).delete_all }
assert_raises(ActiveRecord::ActiveRecordError) { Author.having('SUM(id) < 3').delete_all }
assert_raises(ActiveRecord::ActiveRecordError) { Author.offset(10).delete_all }
@@ -1493,14 +1493,17 @@ class RelationTest < ActiveRecord::TestCase
assert_equal ['Foo', 'Foo'], query.map(&:name)
assert_sql(/DISTINCT/) do
assert_equal ['Foo'], query.distinct.map(&:name)
- assert_equal ['Foo'], query.uniq.map(&:name)
+ assert_deprecated { assert_equal ['Foo'], query.uniq.map(&:name) }
end
assert_sql(/DISTINCT/) do
assert_equal ['Foo'], query.distinct(true).map(&:name)
- assert_equal ['Foo'], query.uniq(true).map(&:name)
+ assert_deprecated { assert_equal ['Foo'], query.uniq(true).map(&:name) }
end
assert_equal ['Foo', 'Foo'], query.distinct(true).distinct(false).map(&:name)
- assert_equal ['Foo', 'Foo'], query.uniq(true).uniq(false).map(&:name)
+
+ assert_deprecated do
+ assert_equal ['Foo', 'Foo'], query.uniq(true).uniq(false).map(&:name)
+ end
end
def test_doesnt_add_having_values_if_options_are_blank
diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md
index d6fa651e39..2fac308d2e 100644
--- a/activesupport/CHANGELOG.md
+++ b/activesupport/CHANGELOG.md
@@ -1,3 +1,25 @@
+* Add a bang version to `ActiveSupport::OrderedOptions` get methods which will raise
+ an `KeyError` if the value is `.blank?`
+
+ Before:
+
+ if (slack_url = Rails.application.secrets.slack_url).present?)
+ # Do something worthwhile
+ else
+ # Raise as important secret password is not specified
+ end
+
+ After:
+
+ slack_url = Rails.application.secrets.slack_url!
+
+ *Aditya Sanghi*, *Gaurish Sharma*
+
+* Remove deprecated `Class#superclass_delegating_accessor`.
+ Use `Class#class_attribute` instead.
+
+ *Akshay Vishnoi*
+
* Patch `Delegator` to work with `#try`.
Fixes #5790.
diff --git a/activesupport/lib/active_support/core_ext/class.rb b/activesupport/lib/active_support/core_ext/class.rb
index c750a10bb2..ef903d59b5 100644
--- a/activesupport/lib/active_support/core_ext/class.rb
+++ b/activesupport/lib/active_support/core_ext/class.rb
@@ -1,3 +1,2 @@
require 'active_support/core_ext/class/attribute'
-require 'active_support/core_ext/class/delegating_attributes'
require 'active_support/core_ext/class/subclasses'
diff --git a/activesupport/lib/active_support/core_ext/class/delegating_attributes.rb b/activesupport/lib/active_support/core_ext/class/delegating_attributes.rb
deleted file mode 100644
index 1c305c5970..0000000000
--- a/activesupport/lib/active_support/core_ext/class/delegating_attributes.rb
+++ /dev/null
@@ -1,45 +0,0 @@
-require 'active_support/core_ext/kernel/singleton_class'
-require 'active_support/core_ext/module/remove_method'
-require 'active_support/core_ext/module/deprecation'
-
-
-class Class
- def superclass_delegating_accessor(name, options = {})
- # Create private _name and _name= methods that can still be used if the public
- # methods are overridden.
- _superclass_delegating_accessor("_#{name}", options)
-
- # Generate the public methods name, name=, and name?.
- # These methods dispatch to the private _name, and _name= methods, making them
- # overridable.
- singleton_class.send(:define_method, name) { send("_#{name}") }
- singleton_class.send(:define_method, "#{name}?") { !!send("_#{name}") }
- singleton_class.send(:define_method, "#{name}=") { |value| send("_#{name}=", value) }
-
- # If an instance_reader is needed, generate public instance methods name and name?.
- if options[:instance_reader] != false
- define_method(name) { send("_#{name}") }
- define_method("#{name}?") { !!send("#{name}") }
- end
- end
-
- deprecate superclass_delegating_accessor: :class_attribute
-
- private
- # Take the object being set and store it in a method. This gives us automatic
- # inheritance behavior, without having to store the object in an instance
- # variable and look up the superclass chain manually.
- def _stash_object_in_method(object, method, instance_reader = true)
- singleton_class.remove_possible_method(method)
- singleton_class.send(:define_method, method) { object }
- remove_possible_method(method)
- define_method(method) { object } if instance_reader
- end
-
- def _superclass_delegating_accessor(name, options = {})
- singleton_class.send(:define_method, "#{name}=") do |value|
- _stash_object_in_method(value, name, options[:instance_reader] != false)
- end
- send("#{name}=", nil)
- end
-end
diff --git a/activesupport/lib/active_support/multibyte/chars.rb b/activesupport/lib/active_support/multibyte/chars.rb
index 4154af8428..45cf6fc1ef 100644
--- a/activesupport/lib/active_support/multibyte/chars.rb
+++ b/activesupport/lib/active_support/multibyte/chars.rb
@@ -86,7 +86,7 @@ module ActiveSupport #:nodoc:
@wrapped_string.split(*args).map { |i| self.class.new(i) }
end
- # Works like like <tt>String#slice!</tt>, but returns an instance of
+ # Works like <tt>String#slice!</tt>, but returns an instance of
# Chars, or nil if the string was not modified.
#
# string = 'Welcome'
diff --git a/activesupport/lib/active_support/ordered_options.rb b/activesupport/lib/active_support/ordered_options.rb
index a33e2c58a9..ebf2a9bc29 100644
--- a/activesupport/lib/active_support/ordered_options.rb
+++ b/activesupport/lib/active_support/ordered_options.rb
@@ -31,7 +31,13 @@ module ActiveSupport
if name_string.chomp!('=')
self[name_string] = args.first
else
- self[name]
+ bangs = name_string.chomp!('!')
+
+ if bangs
+ fetch(name_string.to_sym).presence || raise(KeyError.new("#{name_string} is blank."))
+ else
+ self[name_string]
+ end
end
end
diff --git a/activesupport/test/core_ext/class/delegating_attributes_test.rb b/activesupport/test/core_ext/class/delegating_attributes_test.rb
deleted file mode 100644
index 447b1d10ad..0000000000
--- a/activesupport/test/core_ext/class/delegating_attributes_test.rb
+++ /dev/null
@@ -1,122 +0,0 @@
-require 'abstract_unit'
-require 'active_support/core_ext/class/delegating_attributes'
-
-module DelegatingFixtures
- class Parent
- end
-
- class Child < Parent
- ActiveSupport::Deprecation.silence do
- superclass_delegating_accessor :some_attribute
- end
- end
-
- class Mokopuna < Child
- end
-
- class PercysMom
- ActiveSupport::Deprecation.silence do
- superclass_delegating_accessor :superpower
- end
- end
-
- class Percy < PercysMom
- end
-end
-
-class DelegatingAttributesTest < ActiveSupport::TestCase
- include DelegatingFixtures
- attr_reader :single_class
-
- def setup
- @single_class = Class.new(Object)
- end
-
- def test_simple_accessor_declaration
- assert_deprecated do
- single_class.superclass_delegating_accessor :both
- end
-
- # Class should have accessor and mutator
- # the instance should have an accessor only
- assert_respond_to single_class, :both
- assert_respond_to single_class, :both=
- assert single_class.public_instance_methods.map(&:to_s).include?("both")
- assert !single_class.public_instance_methods.map(&:to_s).include?("both=")
- end
-
- def test_simple_accessor_declaration_with_instance_reader_false
- _instance_methods = single_class.public_instance_methods
-
- assert_deprecated do
- single_class.superclass_delegating_accessor :no_instance_reader, :instance_reader => false
- end
-
- assert_respond_to single_class, :no_instance_reader
- assert_respond_to single_class, :no_instance_reader=
- assert !_instance_methods.include?(:no_instance_reader)
- assert !_instance_methods.include?(:no_instance_reader?)
- assert !_instance_methods.include?(:_no_instance_reader)
- end
-
- def test_working_with_simple_attributes
- assert_deprecated do
- single_class.superclass_delegating_accessor :both
- end
-
- single_class.both = "HMMM"
-
- assert_equal "HMMM", single_class.both
- assert_equal true, single_class.both?
-
- assert_equal "HMMM", single_class.new.both
- assert_equal true, single_class.new.both?
-
- single_class.both = false
- assert_equal false, single_class.both?
- end
-
- def test_child_class_delegates_to_parent_but_can_be_overridden
- parent = Class.new
-
- assert_deprecated do
- parent.superclass_delegating_accessor :both
- end
-
- child = Class.new(parent)
- parent.both = "1"
- assert_equal "1", child.both
-
- child.both = "2"
- assert_equal "1", parent.both
- assert_equal "2", child.both
-
- parent.both = "3"
- assert_equal "3", parent.both
- assert_equal "2", child.both
- end
-
- def test_delegation_stops_at_the_right_level
- assert_nil Percy.superpower
- assert_nil PercysMom.superpower
-
- PercysMom.superpower = :heatvision
- assert_equal :heatvision, Percy.superpower
- end
-
- def test_delegation_stops_for_nil
- Mokopuna.some_attribute = nil
- Child.some_attribute="1"
-
- assert_equal "1", Child.some_attribute
- assert_nil Mokopuna.some_attribute
- ensure
- Child.some_attribute=nil
- end
-
- def test_deprecation_warning
- assert_deprecated(/superclass_delegating_accessor is deprecated/) do
- single_class.superclass_delegating_accessor :test_attribute
- end
- end
-end
diff --git a/activesupport/test/ordered_options_test.rb b/activesupport/test/ordered_options_test.rb
index fdc745b23b..18767a3536 100644
--- a/activesupport/test/ordered_options_test.rb
+++ b/activesupport/test/ordered_options_test.rb
@@ -85,4 +85,19 @@ class OrderedOptionsTest < ActiveSupport::TestCase
assert_equal 42, a.method(:blah=).call(42)
assert_equal 42, a.method(:blah).call
end
+
+ def test_raises_with_bang
+ a = ActiveSupport::OrderedOptions.new
+ a[:foo] = :bar
+ assert a.respond_to?(:foo!)
+
+ assert_nothing_raised { a.foo! }
+ assert_equal a.foo, a.foo!
+
+ assert_raises(KeyError) do
+ a.foo = nil
+ a.foo!
+ end
+ assert_raises(KeyError) { a.non_existing_key! }
+ end
end
diff --git a/guides/source/action_mailer_basics.md b/guides/source/action_mailer_basics.md
index 92a4081233..bf3bf5d19e 100644
--- a/guides/source/action_mailer_basics.md
+++ b/guides/source/action_mailer_basics.md
@@ -344,7 +344,7 @@ The same format can be used to set carbon copy (Cc:) and blind carbon copy
Sometimes you wish to show the name of the person instead of just their email
address when they receive the email. The trick to doing that is to format the
-email address in the format `"Full Name <email>"`.
+email address in the format `"Full Name" <email>`.
```ruby
def welcome_email(user)
diff --git a/guides/source/upgrading_ruby_on_rails.md b/guides/source/upgrading_ruby_on_rails.md
index 3680055f0c..17309d4b47 100644
--- a/guides/source/upgrading_ruby_on_rails.md
+++ b/guides/source/upgrading_ruby_on_rails.md
@@ -940,6 +940,8 @@ Please read [Pull Request #9978](https://github.com/rails/rails/pull/9978) for d
* Rails 4.0 has removed the XML parameters parser. You will need to add the `actionpack-xml_parser` gem if you require this feature.
+* Rails 4.0 changes the default `layout` lookup set using symbols or procs that return nil. To get the "no layout" behavior, return false instead of nil.
+
* Rails 4.0 changes the default memcached client from `memcache-client` to `dalli`. To upgrade, simply add `gem 'dalli'` to your `Gemfile`.
* Rails 4.0 deprecates the `dom_id` and `dom_class` methods in controllers (they are fine in views). You will need to include the `ActionView::RecordIdentifier` module in controllers requiring this feature.