aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Gemfile.lock74
-rw-r--r--RAILS_VERSION2
-rw-r--r--actioncable/CHANGELOG.md11
-rw-r--r--actioncable/lib/action_cable/gem_version.rb2
-rw-r--r--actionmailer/CHANGELOG.md8
-rw-r--r--actionmailer/lib/action_mailer/base.rb13
-rw-r--r--actionmailer/lib/action_mailer/gem_version.rb2
-rw-r--r--actionmailer/lib/action_mailer/railtie.rb1
-rw-r--r--actionmailer/test/caching_test.rb229
-rw-r--r--actionmailer/test/fixtures/caching_mailer/_partial.html.erb3
-rw-r--r--actionmailer/test/fixtures/caching_mailer/fragment_cache.html.erb3
-rw-r--r--actionmailer/test/fixtures/caching_mailer/fragment_cache_in_partials.html.erb1
-rw-r--r--actionmailer/test/fixtures/caching_mailer/skip_fragment_cache_digesting.html.erb3
-rw-r--r--actionmailer/test/mailers/caching_mailer.rb15
-rw-r--r--actionpack/CHANGELOG.md17
-rw-r--r--actionpack/lib/abstract_controller.rb6
-rw-r--r--actionpack/lib/abstract_controller/caching.rb62
-rw-r--r--actionpack/lib/abstract_controller/caching/fragments.rb (renamed from actionpack/lib/action_controller/caching/fragments.rb)11
-rw-r--r--actionpack/lib/action_controller.rb10
-rw-r--r--actionpack/lib/action_controller/caching.rb67
-rw-r--r--actionpack/lib/action_controller/metal/strong_parameters.rb2
-rw-r--r--actionpack/lib/action_controller/test_case.rb2
-rw-r--r--actionpack/lib/action_dispatch/http/request.rb4
-rw-r--r--actionpack/lib/action_dispatch/request/session.rb26
-rw-r--r--actionpack/lib/action_pack/gem_version.rb2
-rw-r--r--actionpack/test/controller/force_ssl_test.rb9
-rw-r--r--actionpack/test/controller/parameters/accessors_test.rb16
-rw-r--r--actionpack/test/dispatch/request/session_test.rb10
-rw-r--r--actionpack/test/dispatch/session/abstract_store_test.rb16
-rw-r--r--actionpack/test/dispatch/session/cache_store_test.rb29
-rw-r--r--actionpack/test/dispatch/session/cookie_store_test.rb34
-rw-r--r--actionpack/test/dispatch/session/mem_cache_store_test.rb31
-rw-r--r--actionpack/test/dispatch/session/test_session_test.rb7
-rw-r--r--actionview/CHANGELOG.md52
-rw-r--r--actionview/lib/action_view/gem_version.rb2
-rw-r--r--activejob/CHANGELOG.md2
-rw-r--r--activejob/lib/active_job/gem_version.rb2
-rw-r--r--activejob/lib/active_job/test_helper.rb582
-rw-r--r--activemodel/CHANGELOG.md5
-rw-r--r--activemodel/lib/active_model/gem_version.rb2
-rw-r--r--activerecord/CHANGELOG.md14
-rw-r--r--activerecord/lib/active_record/gem_version.rb2
-rw-r--r--activerecord/lib/active_record/nested_attributes.rb20
-rw-r--r--activerecord/test/cases/migration_test.rb34
-rw-r--r--activesupport/CHANGELOG.md2
-rw-r--r--activesupport/lib/active_support/deprecation/reporting.rb16
-rw-r--r--activesupport/lib/active_support/gem_version.rb2
-rw-r--r--activesupport/lib/active_support/logger.rb7
-rw-r--r--activesupport/lib/active_support/logger_silence.rb25
-rw-r--r--activesupport/lib/active_support/logger_thread_safe_level.rb31
-rw-r--r--activesupport/lib/active_support/test_case.rb5
-rw-r--r--activesupport/test/logger_test.rb44
-rw-r--r--guides/CHANGELOG.md5
-rw-r--r--guides/source/5_0_release_notes.md6
-rw-r--r--guides/source/action_mailer_basics.md16
-rw-r--r--guides/source/action_view_overview.md2
-rw-r--r--guides/source/asset_pipeline.md4
-rw-r--r--guides/source/configuring.md3
-rw-r--r--guides/source/form_helpers.md2
-rw-r--r--guides/source/rails_application_templates.md22
-rw-r--r--guides/source/working_with_javascript_in_rails.md12
-rw-r--r--railties/CHANGELOG.md12
-rw-r--r--railties/lib/rails/gem_version.rb2
-rw-r--r--railties/lib/rails/generators/actions.rb3
-rw-r--r--railties/lib/rails/generators/app_base.rb11
-rw-r--r--railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt4
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt4
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt1
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt1
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/puma.rb3
-rw-r--r--railties/test/application/configuration_test.rb2
-rw-r--r--railties/test/generators/actions_test.rb48
-rw-r--r--railties/test/generators/app_generator_test.rb4
-rw-r--r--version.rb2
74 files changed, 1185 insertions, 561 deletions
diff --git a/Gemfile.lock b/Gemfile.lock
index d12aa0772f..5d0e815f86 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -28,66 +28,66 @@ GIT
GIT
remote: git://github.com/turbolinks/turbolinks-rails.git
- revision: 1604dcd7bad911f1471d65e4f47cd19d844354f1
+ revision: 65884729016dbb4d032f12bb01b7e7c1ddeb68ac
specs:
- turbolinks (5.0.0.beta1)
+ turbolinks (5.0.0.beta2)
turbolinks-source
PATH
remote: .
specs:
- actioncable (5.0.0.beta2)
- actionpack (= 5.0.0.beta2)
+ actioncable (5.0.0.beta3)
+ actionpack (= 5.0.0.beta3)
nio4r (~> 1.2)
websocket-driver (~> 0.6.1)
- actionmailer (5.0.0.beta2)
- actionpack (= 5.0.0.beta2)
- actionview (= 5.0.0.beta2)
- activejob (= 5.0.0.beta2)
+ actionmailer (5.0.0.beta3)
+ actionpack (= 5.0.0.beta3)
+ actionview (= 5.0.0.beta3)
+ activejob (= 5.0.0.beta3)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 1.0, >= 1.0.5)
- actionpack (5.0.0.beta2)
- actionview (= 5.0.0.beta2)
- activesupport (= 5.0.0.beta2)
+ actionpack (5.0.0.beta3)
+ actionview (= 5.0.0.beta3)
+ activesupport (= 5.0.0.beta3)
rack (~> 2.x)
rack-test (~> 0.6.3)
rails-dom-testing (~> 1.0, >= 1.0.5)
rails-html-sanitizer (~> 1.0, >= 1.0.2)
- actionview (5.0.0.beta2)
- activesupport (= 5.0.0.beta2)
+ actionview (5.0.0.beta3)
+ activesupport (= 5.0.0.beta3)
builder (~> 3.1)
erubis (~> 2.7.0)
rails-dom-testing (~> 1.0, >= 1.0.5)
rails-html-sanitizer (~> 1.0, >= 1.0.2)
- activejob (5.0.0.beta2)
- activesupport (= 5.0.0.beta2)
+ activejob (5.0.0.beta3)
+ activesupport (= 5.0.0.beta3)
globalid (>= 0.3.6)
- activemodel (5.0.0.beta2)
- activesupport (= 5.0.0.beta2)
- activerecord (5.0.0.beta2)
- activemodel (= 5.0.0.beta2)
- activesupport (= 5.0.0.beta2)
+ activemodel (5.0.0.beta3)
+ activesupport (= 5.0.0.beta3)
+ activerecord (5.0.0.beta3)
+ activemodel (= 5.0.0.beta3)
+ activesupport (= 5.0.0.beta3)
arel (~> 7.0)
- activesupport (5.0.0.beta2)
+ activesupport (5.0.0.beta3)
concurrent-ruby (~> 1.0)
i18n (~> 0.7)
minitest (~> 5.1)
tzinfo (~> 1.1)
- rails (5.0.0.beta2)
- actioncable (= 5.0.0.beta2)
- actionmailer (= 5.0.0.beta2)
- actionpack (= 5.0.0.beta2)
- actionview (= 5.0.0.beta2)
- activejob (= 5.0.0.beta2)
- activemodel (= 5.0.0.beta2)
- activerecord (= 5.0.0.beta2)
- activesupport (= 5.0.0.beta2)
+ rails (5.0.0.beta3)
+ actioncable (= 5.0.0.beta3)
+ actionmailer (= 5.0.0.beta3)
+ actionpack (= 5.0.0.beta3)
+ actionview (= 5.0.0.beta3)
+ activejob (= 5.0.0.beta3)
+ activemodel (= 5.0.0.beta3)
+ activerecord (= 5.0.0.beta3)
+ activesupport (= 5.0.0.beta3)
bundler (>= 1.3.0, < 2.0)
- railties (= 5.0.0.beta2)
+ railties (= 5.0.0.beta3)
sprockets-rails (>= 2.0.0)
- railties (5.0.0.beta2)
- actionpack (= 5.0.0.beta2)
- activesupport (= 5.0.0.beta2)
+ railties (5.0.0.beta3)
+ actionpack (= 5.0.0.beta3)
+ activesupport (= 5.0.0.beta3)
method_source
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
@@ -158,7 +158,7 @@ GEM
mime-types (>= 1.16, < 3)
metaclass (0.0.4)
method_source (0.8.2)
- mime-types (2.99)
+ mime-types (2.99.1)
mini_portile2 (2.0.0)
minitest (5.3.3)
mocha (0.14.0)
@@ -239,7 +239,7 @@ GEM
sprockets (3.5.2)
concurrent-ruby (~> 1.0)
rack (> 1, < 3)
- sprockets-rails (3.0.1)
+ sprockets-rails (3.0.2)
actionpack (>= 4.0)
activesupport (>= 4.0)
sprockets (>= 3.0.0)
@@ -252,7 +252,7 @@ GEM
thor (0.19.1)
thread (0.1.7)
thread_safe (0.3.5)
- turbolinks-source (5.0.0.beta1.1)
+ turbolinks-source (5.0.0.beta2)
tzinfo (1.2.2)
thread_safe (~> 0.1)
tzinfo-data (1.2015.7)
diff --git a/RAILS_VERSION b/RAILS_VERSION
index 60b8d0bf66..d727b28ee9 100644
--- a/RAILS_VERSION
+++ b/RAILS_VERSION
@@ -1 +1 @@
-5.0.0.beta2
+5.0.0.beta3
diff --git a/actioncable/CHANGELOG.md b/actioncable/CHANGELOG.md
index bfc229d795..e2e6819f98 100644
--- a/actioncable/CHANGELOG.md
+++ b/actioncable/CHANGELOG.md
@@ -1,7 +1,10 @@
-* Added ActionCable::SubscriptionAdapter::EventedRedis.em_redis_connector/redis_connector and
- ActionCable::SubscriptionAdapter::Redis.redis_connector factory methods for redis connections,
- so you can overwrite with your own initializers. This is used when you want to use different-than-standard Redis adapters,
- like for Makara distributed Redis.
+## Rails 5.0.0.beta3 (February 24, 2016) ##
+
+* Added `em_redis_connector` and `redis_connector` to
+ `ActionCable::SubscriptionAdapter::EventedRedis` and added `redis_connector`
+ to `ActionCable::SubscriptionAdapter::Redis`, so you can overwrite with your
+ own initializers. This is used when you want to use different-than-standard
+ Redis adapters, like for Makara distributed Redis.
*DHH*
diff --git a/actioncable/lib/action_cable/gem_version.rb b/actioncable/lib/action_cable/gem_version.rb
index a71603e61a..67adeefaff 100644
--- a/actioncable/lib/action_cable/gem_version.rb
+++ b/actioncable/lib/action_cable/gem_version.rb
@@ -8,7 +8,7 @@ module ActionCable
MAJOR = 5
MINOR = 0
TINY = 0
- PRE = "beta2"
+ PRE = "beta3"
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
end
diff --git a/actionmailer/CHANGELOG.md b/actionmailer/CHANGELOG.md
index 1531f2b471..604e332dad 100644
--- a/actionmailer/CHANGELOG.md
+++ b/actionmailer/CHANGELOG.md
@@ -1,3 +1,11 @@
+## Rails 5.0.0.beta3 (February 24, 2016) ##
+
+* Add support to fragment cache in Action Mailer.
+
+ Now you can use fragment caching in your mailers views.
+
+ *Stan Lo*
+
* Reset `ActionMailer::Base.deliveries` after every test in
`ActionDispatch::IntegrationTest`.
diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb
index 4259eb0bee..559cd06d91 100644
--- a/actionmailer/lib/action_mailer/base.rb
+++ b/actionmailer/lib/action_mailer/base.rb
@@ -430,6 +430,7 @@ module ActionMailer
include AbstractController::Translation
include AbstractController::AssetPaths
include AbstractController::Callbacks
+ include AbstractController::Caching
include ActionView::Layouts
@@ -947,6 +948,18 @@ module ActionMailer
container.add_part(part)
end
+ # This and #instrument_name is for caching instrument
+ def instrument_payload(key)
+ {
+ mailer: mailer_name,
+ key: key
+ }
+ end
+
+ def instrument_name
+ "action_mailer"
+ end
+
ActiveSupport.run_load_hooks(:action_mailer, self)
end
end
diff --git a/actionmailer/lib/action_mailer/gem_version.rb b/actionmailer/lib/action_mailer/gem_version.rb
index a1ee5fb238..cbe5fc3e64 100644
--- a/actionmailer/lib/action_mailer/gem_version.rb
+++ b/actionmailer/lib/action_mailer/gem_version.rb
@@ -8,7 +8,7 @@ module ActionMailer
MAJOR = 5
MINOR = 0
TINY = 0
- PRE = "beta2"
+ PRE = "beta3"
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
end
diff --git a/actionmailer/lib/action_mailer/railtie.rb b/actionmailer/lib/action_mailer/railtie.rb
index ae89492b0f..215d0199af 100644
--- a/actionmailer/lib/action_mailer/railtie.rb
+++ b/actionmailer/lib/action_mailer/railtie.rb
@@ -25,6 +25,7 @@ module ActionMailer
options.javascripts_dir ||= paths["public/javascripts"].first
options.stylesheets_dir ||= paths["public/stylesheets"].first
options.show_previews = Rails.env.development? if options.show_previews.nil?
+ options.cache_store ||= Rails.cache
if options.show_previews
options.preview_path ||= defined?(Rails.root) ? "#{Rails.root}/test/mailers/previews" : nil
diff --git a/actionmailer/test/caching_test.rb b/actionmailer/test/caching_test.rb
new file mode 100644
index 0000000000..b4344eb167
--- /dev/null
+++ b/actionmailer/test/caching_test.rb
@@ -0,0 +1,229 @@
+require 'fileutils'
+require 'abstract_unit'
+require 'mailers/base_mailer'
+require 'mailers/caching_mailer'
+
+CACHE_DIR = 'test_cache'
+# Don't change '/../temp/' cavalierly or you might hose something you don't want hosed
+FILE_STORE_PATH = File.join(File.dirname(__FILE__), '/../temp/', CACHE_DIR)
+
+class FragmentCachingMailer < ActionMailer::Base
+ abstract!
+
+ def some_action; end
+end
+
+class BaseCachingTest < ActiveSupport::TestCase
+ def setup
+ super
+ @store = ActiveSupport::Cache::MemoryStore.new
+ @mailer = FragmentCachingMailer.new
+ @mailer.perform_caching = true
+ @mailer.cache_store = @store
+ end
+
+ def test_fragment_cache_key
+ assert_equal 'views/what a key', @mailer.fragment_cache_key('what a key')
+ end
+end
+
+class FragmentCachingTest < BaseCachingTest
+ def test_read_fragment_with_caching_enabled
+ @store.write('views/name', 'value')
+ assert_equal 'value', @mailer.read_fragment('name')
+ end
+
+ def test_read_fragment_with_caching_disabled
+ @mailer.perform_caching = false
+ @store.write('views/name', 'value')
+ assert_nil @mailer.read_fragment('name')
+ end
+
+ def test_fragment_exist_with_caching_enabled
+ @store.write('views/name', 'value')
+ assert @mailer.fragment_exist?('name')
+ assert !@mailer.fragment_exist?('other_name')
+ end
+
+ def test_fragment_exist_with_caching_disabled
+ @mailer.perform_caching = false
+ @store.write('views/name', 'value')
+ assert !@mailer.fragment_exist?('name')
+ assert !@mailer.fragment_exist?('other_name')
+ end
+
+ def test_write_fragment_with_caching_enabled
+ assert_nil @store.read('views/name')
+ assert_equal 'value', @mailer.write_fragment('name', 'value')
+ assert_equal 'value', @store.read('views/name')
+ end
+
+ def test_write_fragment_with_caching_disabled
+ assert_nil @store.read('views/name')
+ @mailer.perform_caching = false
+ assert_equal 'value', @mailer.write_fragment('name', 'value')
+ assert_nil @store.read('views/name')
+ end
+
+ def test_expire_fragment_with_simple_key
+ @store.write('views/name', 'value')
+ @mailer.expire_fragment 'name'
+ assert_nil @store.read('views/name')
+ end
+
+ def test_expire_fragment_with_regexp
+ @store.write('views/name', 'value')
+ @store.write('views/another_name', 'another_value')
+ @store.write('views/primalgrasp', 'will not expire ;-)')
+
+ @mailer.expire_fragment(/name/)
+
+ assert_nil @store.read('views/name')
+ assert_nil @store.read('views/another_name')
+ assert_equal 'will not expire ;-)', @store.read('views/primalgrasp')
+ end
+
+ def test_fragment_for
+ @store.write('views/expensive', 'fragment content')
+ fragment_computed = false
+
+ view_context = @mailer.view_context
+
+ buffer = 'generated till now -> '.html_safe
+ buffer << view_context.send(:fragment_for, 'expensive') { fragment_computed = true }
+
+ assert !fragment_computed
+ assert_equal 'generated till now -> fragment content', buffer
+ end
+
+ def test_html_safety
+ assert_nil @store.read('views/name')
+ content = 'value'.html_safe
+ assert_equal content, @mailer.write_fragment('name', content)
+
+ cached = @store.read('views/name')
+ assert_equal content, cached
+ assert_equal String, cached.class
+
+ html_safe = @mailer.read_fragment('name')
+ assert_equal content, html_safe
+ assert html_safe.html_safe?
+ end
+end
+
+class FunctionalFragmentCachingTest < BaseCachingTest
+ def setup
+ super
+ @store = ActiveSupport::Cache::MemoryStore.new
+ @mailer = CachingMailer.new
+ @mailer.perform_caching = true
+ @mailer.cache_store = @store
+ end
+
+ def test_fragment_caching
+ email = @mailer.fragment_cache
+ expected_body = "\"Welcome\""
+
+ assert_match expected_body, email.body.encoded
+ assert_match "\"Welcome\"",
+ @store.read("views/caching/#{template_digest("caching_mailer/fragment_cache")}")
+ end
+
+ def test_fragment_caching_in_partials
+ email = @mailer.fragment_cache_in_partials
+ assert_match(/Old fragment caching in a partial/, email.body.encoded)
+
+ assert_match("Old fragment caching in a partial",
+ @store.read("views/caching/#{template_digest("caching_mailer/_partial")}"))
+ end
+
+ def test_skip_fragment_cache_digesting
+ email = @mailer.skip_fragment_cache_digesting
+ expected_body = "No Digest"
+
+ assert_match expected_body, email.body.encoded
+ assert_match expected_body, @store.read("views/no_digest")
+ end
+
+ private
+
+ def template_digest(name)
+ ActionView::Digestor.digest(name: name, finder: @mailer.lookup_context)
+ end
+end
+
+class CacheHelperOutputBufferTest < BaseCachingTest
+
+ class MockController
+ def read_fragment(name, options)
+ return false
+ end
+
+ def write_fragment(name, fragment, options)
+ fragment
+ end
+ end
+
+ def setup
+ super
+ end
+
+ def test_output_buffer
+ output_buffer = ActionView::OutputBuffer.new
+ controller = MockController.new
+ cache_helper = Class.new do
+ def self.controller; end;
+ def self.output_buffer; end;
+ def self.output_buffer=; end;
+ end
+ cache_helper.extend(ActionView::Helpers::CacheHelper)
+
+ cache_helper.stub :controller, controller do
+ cache_helper.stub :output_buffer, output_buffer do
+ assert_called_with cache_helper, :output_buffer=, [output_buffer.class.new(output_buffer)] do
+ assert_nothing_raised do
+ cache_helper.send :fragment_for, 'Test fragment name', 'Test fragment', &Proc.new{ nil }
+ end
+ end
+ end
+ end
+ end
+
+ def test_safe_buffer
+ output_buffer = ActiveSupport::SafeBuffer.new
+ controller = MockController.new
+ cache_helper = Class.new do
+ def self.controller; end;
+ def self.output_buffer; end;
+ def self.output_buffer=; end;
+ end
+ cache_helper.extend(ActionView::Helpers::CacheHelper)
+
+ cache_helper.stub :controller, controller do
+ cache_helper.stub :output_buffer, output_buffer do
+ assert_called_with cache_helper, :output_buffer=, [output_buffer.class.new(output_buffer)] do
+ assert_nothing_raised do
+ cache_helper.send :fragment_for, 'Test fragment name', 'Test fragment', &Proc.new{ nil }
+ end
+ end
+ end
+ end
+ end
+end
+
+class ViewCacheDependencyTest < BaseCachingTest
+ class NoDependenciesMailer < ActionMailer::Base
+ end
+ class HasDependenciesMailer < ActionMailer::Base
+ view_cache_dependency { "trombone" }
+ view_cache_dependency { "flute" }
+ end
+
+ def test_view_cache_dependencies_are_empty_by_default
+ assert NoDependenciesMailer.new.view_cache_dependencies.empty?
+ end
+
+ def test_view_cache_dependencies_are_listed_in_declaration_order
+ assert_equal %w(trombone flute), HasDependenciesMailer.new.view_cache_dependencies
+ end
+end
diff --git a/actionmailer/test/fixtures/caching_mailer/_partial.html.erb b/actionmailer/test/fixtures/caching_mailer/_partial.html.erb
new file mode 100644
index 0000000000..8e965f52b4
--- /dev/null
+++ b/actionmailer/test/fixtures/caching_mailer/_partial.html.erb
@@ -0,0 +1,3 @@
+<% cache :caching do %>
+ Old fragment caching in a partial
+<% end %>
diff --git a/actionmailer/test/fixtures/caching_mailer/fragment_cache.html.erb b/actionmailer/test/fixtures/caching_mailer/fragment_cache.html.erb
new file mode 100644
index 0000000000..90189627da
--- /dev/null
+++ b/actionmailer/test/fixtures/caching_mailer/fragment_cache.html.erb
@@ -0,0 +1,3 @@
+<% cache :caching do %>
+"Welcome"
+<% end %>
diff --git a/actionmailer/test/fixtures/caching_mailer/fragment_cache_in_partials.html.erb b/actionmailer/test/fixtures/caching_mailer/fragment_cache_in_partials.html.erb
new file mode 100644
index 0000000000..2957d083e8
--- /dev/null
+++ b/actionmailer/test/fixtures/caching_mailer/fragment_cache_in_partials.html.erb
@@ -0,0 +1 @@
+<%= render "partial" %>
diff --git a/actionmailer/test/fixtures/caching_mailer/skip_fragment_cache_digesting.html.erb b/actionmailer/test/fixtures/caching_mailer/skip_fragment_cache_digesting.html.erb
new file mode 100644
index 0000000000..0d52429a81
--- /dev/null
+++ b/actionmailer/test/fixtures/caching_mailer/skip_fragment_cache_digesting.html.erb
@@ -0,0 +1,3 @@
+<%= cache :no_digest, skip_digest: true do %>
+ No Digest
+<% end %>
diff --git a/actionmailer/test/mailers/caching_mailer.rb b/actionmailer/test/mailers/caching_mailer.rb
new file mode 100644
index 0000000000..345d267a36
--- /dev/null
+++ b/actionmailer/test/mailers/caching_mailer.rb
@@ -0,0 +1,15 @@
+class CachingMailer < ActionMailer::Base
+ self.mailer_name = "caching_mailer"
+
+ def fragment_cache
+ mail(subject: "welcome", template_name: "fragment_cache")
+ end
+
+ def fragment_cache_in_partials
+ mail(subject: "welcome", template_name: "fragment_cache_in_partials")
+ end
+
+ def skip_fragment_cache_digesting
+ mail(subject: "welcome", template_name: "skip_fragment_cache_digesting")
+ end
+end
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index d473ab427d..da96aef98b 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -1,3 +1,14 @@
+## Rails 5.0.0.beta3 (February 24, 2016) ##
+
+* Update session to have indifferent access across multiple requests.
+
+ session[:deep][:hash] = "Magic"
+
+ session[:deep][:hash] == "Magic"
+ session[:deep]["hash"] == "Magic"
+
+ *Tom Prats*
+
* Add application/gzip as a default mime type.
*Mehmet Emin İNAÇ*
@@ -37,13 +48,13 @@
end
end
```
-
+
Passing `as: :json` to integration test request helpers will set the format,
content type and encode the parameters as JSON.
-
+
Then on the response side, `parsed_body` will parse the body according to the
content type the response has.
-
+
Currently JSON is the only supported MIME type. Add your own with
`ActionDispatch::IntegrationTest.register_encoder`.
diff --git a/actionpack/lib/abstract_controller.rb b/actionpack/lib/abstract_controller.rb
index 56c4033387..1e57cbaac4 100644
--- a/actionpack/lib/abstract_controller.rb
+++ b/actionpack/lib/abstract_controller.rb
@@ -6,6 +6,7 @@ module AbstractController
extend ActiveSupport::Autoload
autoload :Base
+ autoload :Caching
autoload :Callbacks
autoload :Collector
autoload :DoubleRenderError, "abstract_controller/rendering"
@@ -15,4 +16,9 @@ module AbstractController
autoload :Translation
autoload :AssetPaths
autoload :UrlFor
+
+ def self.eager_load!
+ super
+ AbstractController::Caching.eager_load!
+ end
end
diff --git a/actionpack/lib/abstract_controller/caching.rb b/actionpack/lib/abstract_controller/caching.rb
new file mode 100644
index 0000000000..0dea50889a
--- /dev/null
+++ b/actionpack/lib/abstract_controller/caching.rb
@@ -0,0 +1,62 @@
+module AbstractController
+ module Caching
+ extend ActiveSupport::Concern
+ extend ActiveSupport::Autoload
+
+ eager_autoload do
+ autoload :Fragments
+ end
+
+ module ConfigMethods
+ def cache_store
+ config.cache_store
+ end
+
+ def cache_store=(store)
+ config.cache_store = ActiveSupport::Cache.lookup_store(store)
+ end
+
+ private
+ def cache_configured?
+ perform_caching && cache_store
+ end
+ end
+
+ include ConfigMethods
+ include AbstractController::Caching::Fragments
+
+ included do
+ extend ConfigMethods
+
+ config_accessor :default_static_extension
+ self.default_static_extension ||= '.html'
+
+ config_accessor :perform_caching
+ self.perform_caching = true if perform_caching.nil?
+
+ class_attribute :_view_cache_dependencies
+ self._view_cache_dependencies = []
+ helper_method :view_cache_dependencies if respond_to?(:helper_method)
+ end
+
+ module ClassMethods
+ def view_cache_dependency(&dependency)
+ self._view_cache_dependencies += [dependency]
+ end
+ end
+
+ def view_cache_dependencies
+ self.class._view_cache_dependencies.map { |dep| instance_exec(&dep) }.compact
+ end
+
+ protected
+ # Convenience accessor.
+ def cache(key, options = {}, &block)
+ if cache_configured?
+ cache_store.fetch(ActiveSupport::Cache.expand_cache_key(key, :controller), options, &block)
+ else
+ yield
+ end
+ end
+ end
+end
diff --git a/actionpack/lib/action_controller/caching/fragments.rb b/actionpack/lib/abstract_controller/caching/fragments.rb
index b9ad51a9cf..3257a731ed 100644
--- a/actionpack/lib/action_controller/caching/fragments.rb
+++ b/actionpack/lib/abstract_controller/caching/fragments.rb
@@ -1,4 +1,4 @@
-module ActionController
+module AbstractController
module Caching
# Fragment caching is used for caching various blocks within
# views without caching the entire action as a whole. This is
@@ -135,13 +135,8 @@ module ActionController
end
def instrument_fragment_cache(name, key) # :nodoc:
- payload = {
- controller: controller_name,
- action: action_name,
- key: key
- }
-
- ActiveSupport::Notifications.instrument("#{name}.action_controller", payload) { yield }
+ payload = instrument_payload(key)
+ ActiveSupport::Notifications.instrument("#{name}.#{instrument_name}", payload) { yield }
end
end
end
diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb
index 40f33a9de0..62f5905205 100644
--- a/actionpack/lib/action_controller.rb
+++ b/actionpack/lib/action_controller.rb
@@ -9,12 +9,15 @@ module ActionController
autoload :API
autoload :Base
- autoload :Caching
autoload :Metal
autoload :Middleware
autoload :Renderer
autoload :FormBuilder
+ eager_autoload do
+ autoload :Caching
+ end
+
autoload_under "metal" do
autoload :ConditionalGet
autoload :Cookies
@@ -47,11 +50,6 @@ module ActionController
autoload :TestCase, 'action_controller/test_case'
autoload :TemplateAssertions, 'action_controller/test_case'
-
- def self.eager_load!
- super
- ActionController::Caching.eager_load!
- end
end
# Common Active Support usage in Action Controller
diff --git a/actionpack/lib/action_controller/caching.rb b/actionpack/lib/action_controller/caching.rb
index 0b8fa2ea09..a9a8508abc 100644
--- a/actionpack/lib/action_controller/caching.rb
+++ b/actionpack/lib/action_controller/caching.rb
@@ -1,6 +1,3 @@
-require 'fileutils'
-require 'uri'
-
module ActionController
# \Caching is a cheap way of speeding up slow applications by keeping the result of
# calculations, renderings, and database calls around for subsequent requests.
@@ -23,65 +20,25 @@ module ActionController
# config.action_controller.cache_store = :mem_cache_store, Memcached::Rails.new('localhost:11211')
# config.action_controller.cache_store = MyOwnStore.new('parameter')
module Caching
- extend ActiveSupport::Concern
extend ActiveSupport::Autoload
-
- eager_autoload do
- autoload :Fragments
- end
-
- module ConfigMethods
- def cache_store
- config.cache_store
- end
-
- def cache_store=(store)
- config.cache_store = ActiveSupport::Cache.lookup_store(store)
- end
-
- private
- def cache_configured?
- perform_caching && cache_store
- end
- end
-
- include AbstractController::Callbacks
-
- include ConfigMethods
- include Fragments
+ extend ActiveSupport::Concern
included do
- extend ConfigMethods
-
- config_accessor :default_static_extension
- self.default_static_extension ||= '.html'
-
- config_accessor :perform_caching
- self.perform_caching = true if perform_caching.nil?
-
- class_attribute :_view_cache_dependencies
- self._view_cache_dependencies = []
- helper_method :view_cache_dependencies if respond_to?(:helper_method)
+ include AbstractController::Caching
end
- module ClassMethods
- def view_cache_dependency(&dependency)
- self._view_cache_dependencies += [dependency]
- end
- end
+ private
- def view_cache_dependencies
- self.class._view_cache_dependencies.map { |dep| instance_exec(&dep) }.compact
- end
+ def instrument_payload(key)
+ {
+ controller: controller_name,
+ action: action_name,
+ key: key
+ }
+ end
- protected
- # Convenience accessor.
- def cache(key, options = {}, &block)
- if cache_configured?
- cache_store.fetch(ActiveSupport::Cache.expand_cache_key(key, :controller), options, &block)
- else
- yield
- end
+ def instrument_name
+ "action_controller"
end
end
end
diff --git a/actionpack/lib/action_controller/metal/strong_parameters.rb b/actionpack/lib/action_controller/metal/strong_parameters.rb
index 25ec3cf5b6..a01110d474 100644
--- a/actionpack/lib/action_controller/metal/strong_parameters.rb
+++ b/actionpack/lib/action_controller/metal/strong_parameters.rb
@@ -579,7 +579,7 @@ module ActionController
end
def inspect
- "<#{self.class} #{@parameters}>"
+ "<#{self.class} #{@parameters} permitted: #{@permitted}>"
end
def method_missing(method_sym, *args, &block)
diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb
index 700317614f..6548ce326b 100644
--- a/actionpack/lib/action_controller/test_case.rb
+++ b/actionpack/lib/action_controller/test_case.rb
@@ -176,7 +176,7 @@ module ActionController
def initialize(session = {})
super(nil, nil)
@id = SecureRandom.hex(16)
- @data = stringify_keys(session)
+ @data = session.with_indifferent_access
@loaded = true
end
diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb
index 5427425ef7..316a9f08b7 100644
--- a/actionpack/lib/action_dispatch/http/request.rb
+++ b/actionpack/lib/action_dispatch/http/request.rb
@@ -403,6 +403,10 @@ module ActionDispatch
def commit_flash
end
+ def ssl?
+ super || scheme == 'wss'.freeze
+ end
+
private
def check_method(name)
HTTP_METHOD_LOOKUP[name] || raise(ActionController::UnknownHttpMethod, "#{name}, accepted HTTP methods are #{HTTP_METHODS[0...-1].join(', ')}, and #{HTTP_METHODS[-1]}")
diff --git a/actionpack/lib/action_dispatch/request/session.rb b/actionpack/lib/action_dispatch/request/session.rb
index 42890225fa..38d0da3e67 100644
--- a/actionpack/lib/action_dispatch/request/session.rb
+++ b/actionpack/lib/action_dispatch/request/session.rb
@@ -9,7 +9,7 @@ module ActionDispatch
# Singleton object used to determine if an optional param wasn't specified
Unspecified = Object.new
-
+
# Creates a session hash, merging the properties of the previous session if any
def self.create(store, req, default_options)
session_was = find req
@@ -61,7 +61,7 @@ module ActionDispatch
def initialize(by, req)
@by = by
@req = req
- @delegate = {}
+ @delegate = {}.with_indifferent_access
@loaded = false
@exists = nil # we haven't checked yet
end
@@ -88,13 +88,13 @@ module ActionDispatch
# nil if the given key is not found in the session.
def [](key)
load_for_read!
- @delegate[key.to_s]
+ @delegate[key]
end
# Returns true if the session has the given key or false.
def has_key?(key)
load_for_read!
- @delegate.key?(key.to_s)
+ @delegate.key?(key)
end
alias :key? :has_key?
alias :include? :has_key?
@@ -112,7 +112,7 @@ module ActionDispatch
# Writes given value to given key of the session.
def []=(key, value)
load_for_write!
- @delegate[key.to_s] = value
+ @delegate[key] = value
end
# Clears the session.
@@ -139,13 +139,13 @@ module ActionDispatch
# # => {"session_id"=>"e29b9ea315edf98aad94cc78c34cc9b2", "foo" => "bar"}
def update(hash)
load_for_write!
- @delegate.update stringify_keys(hash)
+ @delegate.update hash
end
# Deletes given key from the session.
def delete(key)
load_for_write!
- @delegate.delete key.to_s
+ @delegate.delete key
end
# Returns value of the given key from the session, or raises +KeyError+
@@ -165,9 +165,9 @@ module ActionDispatch
def fetch(key, default=Unspecified, &block)
load_for_read!
if default == Unspecified
- @delegate.fetch(key.to_s, &block)
+ @delegate.fetch(key, &block)
else
- @delegate.fetch(key.to_s, default, &block)
+ @delegate.fetch(key, default, &block)
end
end
@@ -211,15 +211,9 @@ module ActionDispatch
def load!
id, session = @by.load_session @req
options[:id] = id
- @delegate.replace(stringify_keys(session))
+ @delegate.replace(session)
@loaded = true
end
-
- def stringify_keys(other)
- other.each_with_object({}) { |(key, value), hash|
- hash[key.to_s] = value
- }
- end
end
end
end
diff --git a/actionpack/lib/action_pack/gem_version.rb b/actionpack/lib/action_pack/gem_version.rb
index 778c5482d3..157f401f54 100644
--- a/actionpack/lib/action_pack/gem_version.rb
+++ b/actionpack/lib/action_pack/gem_version.rb
@@ -8,7 +8,7 @@ module ActionPack
MAJOR = 5
MINOR = 0
TINY = 0
- PRE = "beta2"
+ PRE = "beta3"
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
end
diff --git a/actionpack/test/controller/force_ssl_test.rb b/actionpack/test/controller/force_ssl_test.rb
index 22f1cc7c22..03a9c9ae78 100644
--- a/actionpack/test/controller/force_ssl_test.rb
+++ b/actionpack/test/controller/force_ssl_test.rb
@@ -322,3 +322,12 @@ class RedirectToSSLTest < ActionController::TestCase
assert_equal 'ihaz', response.body
end
end
+
+class ForceSSLControllerLevelTest < ActionController::TestCase
+ def test_no_redirect_websocket_ssl_request
+ request.env['rack.url_scheme'] = 'wss'
+ request.env['Upgrade'] = 'websocket'
+ get :cheeseburger
+ assert_response 200
+ end
+end
diff --git a/actionpack/test/controller/parameters/accessors_test.rb b/actionpack/test/controller/parameters/accessors_test.rb
index 4ef5bed30d..cea265f9ab 100644
--- a/actionpack/test/controller/parameters/accessors_test.rb
+++ b/actionpack/test/controller/parameters/accessors_test.rb
@@ -4,6 +4,8 @@ require 'active_support/core_ext/hash/transform_values'
class ParametersAccessorsTest < ActiveSupport::TestCase
setup do
+ ActionController::Parameters.permit_all_parameters = false
+
@params = ActionController::Parameters.new(
person: {
age: '32',
@@ -176,12 +178,20 @@ class ParametersAccessorsTest < ActiveSupport::TestCase
assert(@params != false)
end
- test "inspect shows both class name and parameters" do
+ test "inspect shows both class name, parameters and permitted flag" do
assert_equal(
'<ActionController::Parameters {"person"=>{"age"=>"32", '\
- '"name"=>{"first"=>"David", "last"=>"Heinemeier Hansson"}, ' \
- '"addresses"=>[{"city"=>"Chicago", "state"=>"Illinois"}]}}>',
+ '"name"=>{"first"=>"David", "last"=>"Heinemeier Hansson"}, ' \
+ '"addresses"=>[{"city"=>"Chicago", "state"=>"Illinois"}]}} permitted: false>',
@params.inspect
)
end
+
+ test "inspect prints updated permitted flag in the output" do
+ assert_match(/permitted: false/, @params.inspect)
+
+ @params.permit!
+
+ assert_match(/permitted: true/, @params.inspect)
+ end
end
diff --git a/actionpack/test/dispatch/request/session_test.rb b/actionpack/test/dispatch/request/session_test.rb
index 7dcbcc5c21..3433d82791 100644
--- a/actionpack/test/dispatch/request/session_test.rb
+++ b/actionpack/test/dispatch/request/session_test.rb
@@ -105,6 +105,16 @@ module ActionDispatch
end
end
+ def test_indifferent_access
+ s = Session.create(store, req, {})
+
+ s[:one] = { test: "deep" }
+ s[:two] = { "test" => "deep" }
+
+ assert_equal 'deep', s[:one]["test"]
+ assert_equal 'deep', s[:two][:test]
+ end
+
private
def store
Class.new {
diff --git a/actionpack/test/dispatch/session/abstract_store_test.rb b/actionpack/test/dispatch/session/abstract_store_test.rb
index d38d1bbce6..c9ce5cad42 100644
--- a/actionpack/test/dispatch/session/abstract_store_test.rb
+++ b/actionpack/test/dispatch/session/abstract_store_test.rb
@@ -46,6 +46,22 @@ module ActionDispatch
assert_equal session.to_hash, session1.to_hash
end
+ def test_previous_session_has_indifferent_access
+ env = {}
+ as = MemoryStore.new app
+ as.call(env)
+
+ assert @env
+ session = Request::Session.find ActionDispatch::Request.new @env
+ session[:foo] = { bar: "baz" }
+
+ as.call(@env)
+ session = Request::Session.find ActionDispatch::Request.new @env
+
+ assert_equal session[:foo][:bar], "baz"
+ assert_equal session[:foo]["bar"], "baz"
+ end
+
private
def app(&block)
@env = nil
diff --git a/actionpack/test/dispatch/session/cache_store_test.rb b/actionpack/test/dispatch/session/cache_store_test.rb
index dbb996973d..b911392cf1 100644
--- a/actionpack/test/dispatch/session/cache_store_test.rb
+++ b/actionpack/test/dispatch/session/cache_store_test.rb
@@ -12,6 +12,11 @@ class CacheStoreTest < ActionDispatch::IntegrationTest
head :ok
end
+ def set_deep_session_value
+ session[:foo] = { bar: "baz" }
+ head :ok
+ end
+
def set_serialized_session_value
session[:foo] = SessionAutoloadTest::Foo.new
head :ok
@@ -21,6 +26,14 @@ class CacheStoreTest < ActionDispatch::IntegrationTest
render plain: "foo: #{session[:foo].inspect}"
end
+ def get_deep_session_value_with_symbol
+ render plain: "foo: { bar: #{session[:foo][:bar].inspect} }"
+ end
+
+ def get_deep_session_value_with_string
+ render plain: "foo: { \"bar\" => #{session[:foo]["bar"].inspect} }"
+ end
+
def get_session_id
render plain: "#{request.session.id}"
end
@@ -160,6 +173,22 @@ class CacheStoreTest < ActionDispatch::IntegrationTest
end
end
+ def test_previous_session_has_indifferent_access
+ with_test_route_set do
+ get '/set_deep_session_value'
+ assert_response :success
+ assert cookies['_session_id']
+
+ get '/get_deep_session_value_with_symbol'
+ assert_response :success
+ assert_equal 'foo: { bar: "baz" }', response.body
+
+ get '/get_deep_session_value_with_string'
+ assert_response :success
+ assert_equal 'foo: { "bar" => "baz" }', response.body
+ end
+ end
+
private
def with_test_route_set
with_routing do |set|
diff --git a/actionpack/test/dispatch/session/cookie_store_test.rb b/actionpack/test/dispatch/session/cookie_store_test.rb
index f07e215e3a..71402b021a 100644
--- a/actionpack/test/dispatch/session/cookie_store_test.rb
+++ b/actionpack/test/dispatch/session/cookie_store_test.rb
@@ -24,10 +24,23 @@ class CookieStoreTest < ActionDispatch::IntegrationTest
render plain: Rack::Utils.escape(Verifier.generate(session.to_hash))
end
+ def set_deep_session_value
+ session[:foo] = { bar: "baz" }
+ render plain: Rack::Utils.escape(Verifier.generate(session.to_hash))
+ end
+
def get_session_value
render plain: "foo: #{session[:foo].inspect}"
end
+ def get_deep_session_value_with_symbol
+ render plain: "foo: { bar: #{session[:foo][:bar].inspect} }"
+ end
+
+ def get_deep_session_value_with_string
+ render plain: "foo: { \"bar\" => #{session[:foo]["bar"].inspect} }"
+ end
+
def get_session_id
render plain: "id: #{request.session.id}"
end
@@ -81,6 +94,15 @@ class CookieStoreTest < ActionDispatch::IntegrationTest
end
end
+ def test_session_indifferent_access
+ with_test_route_set do
+ cookies[SessionKey] = SignedBar
+ get '/get_session_value'
+ assert_response :success
+ assert_equal 'foo: "bar"', response.body
+ end
+ end
+
def test_getting_session_id
with_test_route_set do
cookies[SessionKey] = SignedBar
@@ -332,6 +354,18 @@ class CookieStoreTest < ActionDispatch::IntegrationTest
end
end
+ def test_previous_session_has_indifferent_access
+ with_test_route_set do
+ get '/set_deep_session_value'
+
+ get '/get_deep_session_value_with_symbol'
+ assert_equal 'foo: { bar: "baz" }', response.body
+
+ get '/get_deep_session_value_with_string'
+ assert_equal 'foo: { "bar" => "baz" }', response.body
+ end
+ end
+
private
# Overwrite get to send SessionSecret in env hash
diff --git a/actionpack/test/dispatch/session/mem_cache_store_test.rb b/actionpack/test/dispatch/session/mem_cache_store_test.rb
index 3fed9bad4f..2e6b42856f 100644
--- a/actionpack/test/dispatch/session/mem_cache_store_test.rb
+++ b/actionpack/test/dispatch/session/mem_cache_store_test.rb
@@ -13,6 +13,11 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest
head :ok
end
+ def set_deep_session_value
+ session[:foo] = { bar: "baz" }
+ head :ok
+ end
+
def set_serialized_session_value
session[:foo] = SessionAutoloadTest::Foo.new
head :ok
@@ -22,6 +27,14 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest
render plain: "foo: #{session[:foo].inspect}"
end
+ def get_deep_session_value_with_symbol
+ render plain: "foo: { bar: #{session[:foo][:bar].inspect} }"
+ end
+
+ def get_deep_session_value_with_string
+ render plain: "foo: { \"bar\" => #{session[:foo]["bar"].inspect} }"
+ end
+
def get_session_id
render plain: "#{request.session.id}"
end
@@ -179,6 +192,24 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest
rescue Dalli::RingError => ex
skip ex.message, ex.backtrace
end
+
+ def test_previous_session_has_indifferent_access
+ with_test_route_set do
+ get '/set_deep_session_value'
+ assert_response :success
+ assert cookies['_session_id']
+
+ get '/get_deep_session_value_with_symbol'
+ assert_response :success
+ assert_equal 'foo: { bar: "baz" }', response.body
+
+ get '/get_deep_session_value_with_string'
+ assert_response :success
+ assert_equal 'foo: { "bar" => "baz" }', response.body
+ end
+ rescue Dalli::RingError => ex
+ skip ex.message, ex.backtrace
+ end
rescue LoadError, RuntimeError, Dalli::DalliError
$stderr.puts "Skipping MemCacheStoreTest tests. Start memcached and try again."
end
diff --git a/actionpack/test/dispatch/session/test_session_test.rb b/actionpack/test/dispatch/session/test_session_test.rb
index 3e61d123e3..332c2ae3c8 100644
--- a/actionpack/test/dispatch/session/test_session_test.rb
+++ b/actionpack/test/dispatch/session/test_session_test.rb
@@ -60,4 +60,11 @@ class ActionController::TestSessionTest < ActiveSupport::TestCase
session = ActionController::TestSession.new(one: '1')
assert_equal(2, session.fetch('2') { |key| key.to_i })
end
+
+ def test_fetch_returns_indifferent_access
+ session = ActionController::TestSession.new(three: { two: '1' })
+ three = session.fetch(:three)
+ assert_equal('1', three[:two])
+ assert_equal('1', three["two"])
+ end
end
diff --git a/actionview/CHANGELOG.md b/actionview/CHANGELOG.md
index bd7ce14e04..d084f2b1e0 100644
--- a/actionview/CHANGELOG.md
+++ b/actionview/CHANGELOG.md
@@ -1,3 +1,30 @@
+## Rails 5.0.0.beta3 (February 24, 2016) ##
+
+* Collection rendering can cache and fetch multiple partials at once.
+
+ Collections rendered as:
+
+ ```ruby
+ <%= render partial: 'notifications/notification', collection: @notifications, as: :notification, cached: true %>
+ ```
+
+ will read several partials from cache at once. The templates in the collection
+ that haven't been cached already will automatically be written to cache. Works
+ great alongside individual template fragment caching. For instance if the
+ template the collection renders is cached like:
+
+ ```ruby
+ # notifications/_notification.html.erb
+ <% cache notification do %>
+ <%# ... %>
+ <% end %>
+ ```
+
+ Then any collection renders shares that cache when attempting to read multiple
+ ones at once.
+
+ *Kasper Timm Hansen*
+
* Add support for nested hashes/arrays to `:params` option of `button_to` helper.
*James Coleman*
@@ -197,31 +224,6 @@
*Ulisses Almeida*
-* Collection rendering can cache and fetch multiple partials at once.
-
- Collections rendered as:
-
- ```ruby
- <%= render partial: 'notifications/notification', collection: @notifications, as: :notification, cached: true %>
- ```
-
- will read several partials from cache at once. The templates in the collection
- that haven't been cached already will automatically be written to cache. Works
- great alongside individual template fragment caching. For instance if the
- template the collection renders is cached like:
-
- ```ruby
- # notifications/_notification.html.erb
- <% cache notification do %>
- <%# ... %>
- <% end %>
- ```
-
- Then any collection renders shares that cache when attempting to read multiple
- ones at once.
-
- *Kasper Timm Hansen*
-
* Fixed a dependency tracker bug that caused template dependencies not
count layouts as dependencies for partials.
diff --git a/actionview/lib/action_view/gem_version.rb b/actionview/lib/action_view/gem_version.rb
index bb5c96cb39..efb565bf59 100644
--- a/actionview/lib/action_view/gem_version.rb
+++ b/actionview/lib/action_view/gem_version.rb
@@ -8,7 +8,7 @@ module ActionView
MAJOR = 5
MINOR = 0
TINY = 0
- PRE = "beta2"
+ PRE = "beta3"
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
end
diff --git a/activejob/CHANGELOG.md b/activejob/CHANGELOG.md
index 229ef03879..913164fbc5 100644
--- a/activejob/CHANGELOG.md
+++ b/activejob/CHANGELOG.md
@@ -1,3 +1,5 @@
+## Rails 5.0.0.beta3 (February 24, 2016) ##
+
* Change the default adapter from inline to async. It's a better default as tests will then not mistakenly
come to rely on behavior happening synchronously. This is especially important with things like jobs kicked off
in Active Record lifecycle callbacks.
diff --git a/activejob/lib/active_job/gem_version.rb b/activejob/lib/active_job/gem_version.rb
index bc88221027..be4fabf545 100644
--- a/activejob/lib/active_job/gem_version.rb
+++ b/activejob/lib/active_job/gem_version.rb
@@ -8,7 +8,7 @@ module ActiveJob
MAJOR = 5
MINOR = 0
TINY = 0
- PRE = "beta2"
+ PRE = "beta3"
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
end
diff --git a/activejob/lib/active_job/test_helper.rb b/activejob/lib/active_job/test_helper.rb
index ed0c05c1e5..e06b98736d 100644
--- a/activejob/lib/active_job/test_helper.rb
+++ b/activejob/lib/active_job/test_helper.rb
@@ -4,325 +4,321 @@ require 'active_support/core_ext/hash/keys'
module ActiveJob
# Provides helper methods for testing Active Job
module TestHelper
- extend ActiveSupport::Concern
+ delegate :enqueued_jobs, :enqueued_jobs=,
+ :performed_jobs, :performed_jobs=,
+ to: :queue_adapter
- included do
- def before_setup # :nodoc:
- test_adapter = ActiveJob::QueueAdapters::TestAdapter.new
+ def before_setup # :nodoc:
+ test_adapter = ActiveJob::QueueAdapters::TestAdapter.new
- @old_queue_adapters = (ActiveJob::Base.subclasses << ActiveJob::Base).select do |klass|
- # only override explicitly set adapters, a quirk of `class_attribute`
- klass.singleton_class.public_instance_methods(false).include?(:_queue_adapter)
- end.map do |klass|
- [klass, klass.queue_adapter].tap do
- klass.queue_adapter = test_adapter
- end
+ @old_queue_adapters = (ActiveJob::Base.subclasses << ActiveJob::Base).select do |klass|
+ # only override explicitly set adapters, a quirk of `class_attribute`
+ klass.singleton_class.public_instance_methods(false).include?(:_queue_adapter)
+ end.map do |klass|
+ [klass, klass.queue_adapter].tap do
+ klass.queue_adapter = test_adapter
end
-
- clear_enqueued_jobs
- clear_performed_jobs
- super
end
- def after_teardown # :nodoc:
- super
- @old_queue_adapters.each do |(klass, adapter)|
- klass.queue_adapter = adapter
- end
- end
+ clear_enqueued_jobs
+ clear_performed_jobs
+ super
+ end
- # Asserts that the number of enqueued jobs matches the given number.
- #
- # def test_jobs
- # assert_enqueued_jobs 0
- # HelloJob.perform_later('david')
- # assert_enqueued_jobs 1
- # HelloJob.perform_later('abdelkader')
- # assert_enqueued_jobs 2
- # end
- #
- # If a block is passed, that block should cause the specified number of
- # jobs to be enqueued.
- #
- # def test_jobs_again
- # assert_enqueued_jobs 1 do
- # HelloJob.perform_later('cristian')
- # end
- #
- # assert_enqueued_jobs 2 do
- # HelloJob.perform_later('aaron')
- # HelloJob.perform_later('rafael')
- # end
- # end
- #
- # The number of times a specific job is enqueued can be asserted.
- #
- # def test_logging_job
- # assert_enqueued_jobs 1, only: LoggingJob do
- # LoggingJob.perform_later
- # HelloJob.perform_later('jeremy')
- # end
- # end
- def assert_enqueued_jobs(number, only: nil)
- if block_given?
- original_count = enqueued_jobs_size(only: only)
- yield
- new_count = enqueued_jobs_size(only: only)
- assert_equal number, new_count - original_count, "#{number} jobs expected, but #{new_count - original_count} were enqueued"
- else
- actual_count = enqueued_jobs_size(only: only)
- assert_equal number, actual_count, "#{number} jobs expected, but #{actual_count} were enqueued"
- end
+ def after_teardown # :nodoc:
+ super
+ @old_queue_adapters.each do |(klass, adapter)|
+ klass.queue_adapter = adapter
end
+ end
- # Asserts that no jobs have been enqueued.
- #
- # def test_jobs
- # assert_no_enqueued_jobs
- # HelloJob.perform_later('jeremy')
- # assert_enqueued_jobs 1
- # end
- #
- # If a block is passed, that block should not cause any job to be enqueued.
- #
- # def test_jobs_again
- # assert_no_enqueued_jobs do
- # # No job should be enqueued from this block
- # end
- # end
- #
- # It can be asserted that no jobs of a specific kind are enqueued:
- #
- # def test_no_logging
- # assert_no_enqueued_jobs only: LoggingJob do
- # HelloJob.perform_later('jeremy')
- # end
- # end
- #
- # Note: This assertion is simply a shortcut for:
- #
- # assert_enqueued_jobs 0, &block
- def assert_no_enqueued_jobs(only: nil, &block)
- assert_enqueued_jobs 0, only: only, &block
+ # Asserts that the number of enqueued jobs matches the given number.
+ #
+ # def test_jobs
+ # assert_enqueued_jobs 0
+ # HelloJob.perform_later('david')
+ # assert_enqueued_jobs 1
+ # HelloJob.perform_later('abdelkader')
+ # assert_enqueued_jobs 2
+ # end
+ #
+ # If a block is passed, that block should cause the specified number of
+ # jobs to be enqueued.
+ #
+ # def test_jobs_again
+ # assert_enqueued_jobs 1 do
+ # HelloJob.perform_later('cristian')
+ # end
+ #
+ # assert_enqueued_jobs 2 do
+ # HelloJob.perform_later('aaron')
+ # HelloJob.perform_later('rafael')
+ # end
+ # end
+ #
+ # The number of times a specific job is enqueued can be asserted.
+ #
+ # def test_logging_job
+ # assert_enqueued_jobs 1, only: LoggingJob do
+ # LoggingJob.perform_later
+ # HelloJob.perform_later('jeremy')
+ # end
+ # end
+ def assert_enqueued_jobs(number, only: nil)
+ if block_given?
+ original_count = enqueued_jobs_size(only: only)
+ yield
+ new_count = enqueued_jobs_size(only: only)
+ assert_equal number, new_count - original_count, "#{number} jobs expected, but #{new_count - original_count} were enqueued"
+ else
+ actual_count = enqueued_jobs_size(only: only)
+ assert_equal number, actual_count, "#{number} jobs expected, but #{actual_count} were enqueued"
end
+ end
- # Asserts that the number of performed jobs matches the given number.
- # If no block is passed, <tt>perform_enqueued_jobs</tt>
- # must be called around the job call.
- #
- # def test_jobs
- # assert_performed_jobs 0
- #
- # perform_enqueued_jobs do
- # HelloJob.perform_later('xavier')
- # end
- # assert_performed_jobs 1
- #
- # perform_enqueued_jobs do
- # HelloJob.perform_later('yves')
- # assert_performed_jobs 2
- # end
- # end
- #
- # If a block is passed, that block should cause the specified number of
- # jobs to be performed.
- #
- # def test_jobs_again
- # assert_performed_jobs 1 do
- # HelloJob.perform_later('robin')
- # end
- #
- # assert_performed_jobs 2 do
- # HelloJob.perform_later('carlos')
- # HelloJob.perform_later('sean')
- # end
- # end
- #
- # The block form supports filtering. If the :only option is specified,
- # then only the listed job(s) will be performed.
- #
- # def test_hello_job
- # assert_performed_jobs 1, only: HelloJob do
- # HelloJob.perform_later('jeremy')
- # LoggingJob.perform_later
- # end
- # end
- #
- # An array may also be specified, to support testing multiple jobs.
- #
- # def test_hello_and_logging_jobs
- # assert_nothing_raised do
- # assert_performed_jobs 2, only: [HelloJob, LoggingJob] do
- # HelloJob.perform_later('jeremy')
- # LoggingJob.perform_later('stewie')
- # RescueJob.perform_later('david')
- # end
- # end
- # end
- def assert_performed_jobs(number, only: nil)
- if block_given?
- original_count = performed_jobs.size
- perform_enqueued_jobs(only: only) { yield }
- new_count = performed_jobs.size
- assert_equal number, new_count - original_count,
- "#{number} jobs expected, but #{new_count - original_count} were performed"
- else
- performed_jobs_size = performed_jobs.size
- assert_equal number, performed_jobs_size, "#{number} jobs expected, but #{performed_jobs_size} were performed"
- end
- end
+ # Asserts that no jobs have been enqueued.
+ #
+ # def test_jobs
+ # assert_no_enqueued_jobs
+ # HelloJob.perform_later('jeremy')
+ # assert_enqueued_jobs 1
+ # end
+ #
+ # If a block is passed, that block should not cause any job to be enqueued.
+ #
+ # def test_jobs_again
+ # assert_no_enqueued_jobs do
+ # # No job should be enqueued from this block
+ # end
+ # end
+ #
+ # It can be asserted that no jobs of a specific kind are enqueued:
+ #
+ # def test_no_logging
+ # assert_no_enqueued_jobs only: LoggingJob do
+ # HelloJob.perform_later('jeremy')
+ # end
+ # end
+ #
+ # Note: This assertion is simply a shortcut for:
+ #
+ # assert_enqueued_jobs 0, &block
+ def assert_no_enqueued_jobs(only: nil, &block)
+ assert_enqueued_jobs 0, only: only, &block
+ end
- # Asserts that no jobs have been performed.
- #
- # def test_jobs
- # assert_no_performed_jobs
- #
- # perform_enqueued_jobs do
- # HelloJob.perform_later('matthew')
- # assert_performed_jobs 1
- # end
- # end
- #
- # If a block is passed, that block should not cause any job to be performed.
- #
- # def test_jobs_again
- # assert_no_performed_jobs do
- # # No job should be performed from this block
- # end
- # end
- #
- # The block form supports filtering. If the :only option is specified,
- # then only the listed job(s) will be performed.
- #
- # def test_hello_job
- # assert_performed_jobs 1, only: HelloJob do
- # HelloJob.perform_later('jeremy')
- # LoggingJob.perform_later
- # end
- # end
- #
- # An array may also be specified, to support testing multiple jobs.
- #
- # def test_hello_and_logging_jobs
- # assert_nothing_raised do
- # assert_performed_jobs 2, only: [HelloJob, LoggingJob] do
- # HelloJob.perform_later('jeremy')
- # LoggingJob.perform_later('stewie')
- # RescueJob.perform_later('david')
- # end
- # end
- # end
- #
- # Note: This assertion is simply a shortcut for:
- #
- # assert_performed_jobs 0, &block
- def assert_no_performed_jobs(only: nil, &block)
- assert_performed_jobs 0, only: only, &block
+ # Asserts that the number of performed jobs matches the given number.
+ # If no block is passed, <tt>perform_enqueued_jobs</tt>
+ # must be called around the job call.
+ #
+ # def test_jobs
+ # assert_performed_jobs 0
+ #
+ # perform_enqueued_jobs do
+ # HelloJob.perform_later('xavier')
+ # end
+ # assert_performed_jobs 1
+ #
+ # perform_enqueued_jobs do
+ # HelloJob.perform_later('yves')
+ # assert_performed_jobs 2
+ # end
+ # end
+ #
+ # If a block is passed, that block should cause the specified number of
+ # jobs to be performed.
+ #
+ # def test_jobs_again
+ # assert_performed_jobs 1 do
+ # HelloJob.perform_later('robin')
+ # end
+ #
+ # assert_performed_jobs 2 do
+ # HelloJob.perform_later('carlos')
+ # HelloJob.perform_later('sean')
+ # end
+ # end
+ #
+ # The block form supports filtering. If the :only option is specified,
+ # then only the listed job(s) will be performed.
+ #
+ # def test_hello_job
+ # assert_performed_jobs 1, only: HelloJob do
+ # HelloJob.perform_later('jeremy')
+ # LoggingJob.perform_later
+ # end
+ # end
+ #
+ # An array may also be specified, to support testing multiple jobs.
+ #
+ # def test_hello_and_logging_jobs
+ # assert_nothing_raised do
+ # assert_performed_jobs 2, only: [HelloJob, LoggingJob] do
+ # HelloJob.perform_later('jeremy')
+ # LoggingJob.perform_later('stewie')
+ # RescueJob.perform_later('david')
+ # end
+ # end
+ # end
+ def assert_performed_jobs(number, only: nil)
+ if block_given?
+ original_count = performed_jobs.size
+ perform_enqueued_jobs(only: only) { yield }
+ new_count = performed_jobs.size
+ assert_equal number, new_count - original_count,
+ "#{number} jobs expected, but #{new_count - original_count} were performed"
+ else
+ performed_jobs_size = performed_jobs.size
+ assert_equal number, performed_jobs_size, "#{number} jobs expected, but #{performed_jobs_size} were performed"
end
+ end
- # Asserts that the job passed in the block has been enqueued with the given arguments.
- #
- # def test_assert_enqueued_with
- # assert_enqueued_with(job: MyJob, args: [1,2,3], queue: 'low') do
- # MyJob.perform_later(1,2,3)
- # end
- #
- # assert_enqueued_with(job: MyJob, at: Date.tomorrow.noon) do
- # MyJob.set(wait_until: Date.tomorrow.noon).perform_later
- # end
- # end
- def assert_enqueued_with(args = {})
- original_enqueued_jobs_count = enqueued_jobs.count
- args.assert_valid_keys(:job, :args, :at, :queue)
- serialized_args = serialize_args_for_assertion(args)
- yield
- in_block_jobs = enqueued_jobs.drop(original_enqueued_jobs_count)
- matching_job = in_block_jobs.find do |job|
- serialized_args.all? { |key, value| value == job[key] }
- end
- assert matching_job, "No enqueued job found with #{args}"
- instantiate_job(matching_job)
- end
+ # Asserts that no jobs have been performed.
+ #
+ # def test_jobs
+ # assert_no_performed_jobs
+ #
+ # perform_enqueued_jobs do
+ # HelloJob.perform_later('matthew')
+ # assert_performed_jobs 1
+ # end
+ # end
+ #
+ # If a block is passed, that block should not cause any job to be performed.
+ #
+ # def test_jobs_again
+ # assert_no_performed_jobs do
+ # # No job should be performed from this block
+ # end
+ # end
+ #
+ # The block form supports filtering. If the :only option is specified,
+ # then only the listed job(s) will be performed.
+ #
+ # def test_hello_job
+ # assert_performed_jobs 1, only: HelloJob do
+ # HelloJob.perform_later('jeremy')
+ # LoggingJob.perform_later
+ # end
+ # end
+ #
+ # An array may also be specified, to support testing multiple jobs.
+ #
+ # def test_hello_and_logging_jobs
+ # assert_nothing_raised do
+ # assert_performed_jobs 2, only: [HelloJob, LoggingJob] do
+ # HelloJob.perform_later('jeremy')
+ # LoggingJob.perform_later('stewie')
+ # RescueJob.perform_later('david')
+ # end
+ # end
+ # end
+ #
+ # Note: This assertion is simply a shortcut for:
+ #
+ # assert_performed_jobs 0, &block
+ def assert_no_performed_jobs(only: nil, &block)
+ assert_performed_jobs 0, only: only, &block
+ end
- # Asserts that the job passed in the block has been performed with the given arguments.
- #
- # def test_assert_performed_with
- # assert_performed_with(job: MyJob, args: [1,2,3], queue: 'high') do
- # MyJob.perform_later(1,2,3)
- # end
- #
- # assert_performed_with(job: MyJob, at: Date.tomorrow.noon) do
- # MyJob.set(wait_until: Date.tomorrow.noon).perform_later
- # end
- # end
- def assert_performed_with(args = {})
- original_performed_jobs_count = performed_jobs.count
- args.assert_valid_keys(:job, :args, :at, :queue)
- serialized_args = serialize_args_for_assertion(args)
- perform_enqueued_jobs { yield }
- in_block_jobs = performed_jobs.drop(original_performed_jobs_count)
- matching_job = in_block_jobs.find do |job|
- serialized_args.all? { |key, value| value == job[key] }
- end
- assert matching_job, "No performed job found with #{args}"
- instantiate_job(matching_job)
+ # Asserts that the job passed in the block has been enqueued with the given arguments.
+ #
+ # def test_assert_enqueued_with
+ # assert_enqueued_with(job: MyJob, args: [1,2,3], queue: 'low') do
+ # MyJob.perform_later(1,2,3)
+ # end
+ #
+ # assert_enqueued_with(job: MyJob, at: Date.tomorrow.noon) do
+ # MyJob.set(wait_until: Date.tomorrow.noon).perform_later
+ # end
+ # end
+ def assert_enqueued_with(args = {})
+ original_enqueued_jobs_count = enqueued_jobs.count
+ args.assert_valid_keys(:job, :args, :at, :queue)
+ serialized_args = serialize_args_for_assertion(args)
+ yield
+ in_block_jobs = enqueued_jobs.drop(original_enqueued_jobs_count)
+ matching_job = in_block_jobs.find do |job|
+ serialized_args.all? { |key, value| value == job[key] }
end
+ assert matching_job, "No enqueued job found with #{args}"
+ instantiate_job(matching_job)
+ end
- def perform_enqueued_jobs(only: nil)
- old_perform_enqueued_jobs = queue_adapter.perform_enqueued_jobs
- old_perform_enqueued_at_jobs = queue_adapter.perform_enqueued_at_jobs
- old_filter = queue_adapter.filter
-
- begin
- queue_adapter.perform_enqueued_jobs = true
- queue_adapter.perform_enqueued_at_jobs = true
- queue_adapter.filter = only
- yield
- ensure
- queue_adapter.perform_enqueued_jobs = old_perform_enqueued_jobs
- queue_adapter.perform_enqueued_at_jobs = old_perform_enqueued_at_jobs
- queue_adapter.filter = old_filter
- end
+ # Asserts that the job passed in the block has been performed with the given arguments.
+ #
+ # def test_assert_performed_with
+ # assert_performed_with(job: MyJob, args: [1,2,3], queue: 'high') do
+ # MyJob.perform_later(1,2,3)
+ # end
+ #
+ # assert_performed_with(job: MyJob, at: Date.tomorrow.noon) do
+ # MyJob.set(wait_until: Date.tomorrow.noon).perform_later
+ # end
+ # end
+ def assert_performed_with(args = {})
+ original_performed_jobs_count = performed_jobs.count
+ args.assert_valid_keys(:job, :args, :at, :queue)
+ serialized_args = serialize_args_for_assertion(args)
+ perform_enqueued_jobs { yield }
+ in_block_jobs = performed_jobs.drop(original_performed_jobs_count)
+ matching_job = in_block_jobs.find do |job|
+ serialized_args.all? { |key, value| value == job[key] }
end
+ assert matching_job, "No performed job found with #{args}"
+ instantiate_job(matching_job)
+ end
+
+ def perform_enqueued_jobs(only: nil)
+ old_perform_enqueued_jobs = queue_adapter.perform_enqueued_jobs
+ old_perform_enqueued_at_jobs = queue_adapter.perform_enqueued_at_jobs
+ old_filter = queue_adapter.filter
- def queue_adapter
- ActiveJob::Base.queue_adapter
+ begin
+ queue_adapter.perform_enqueued_jobs = true
+ queue_adapter.perform_enqueued_at_jobs = true
+ queue_adapter.filter = only
+ yield
+ ensure
+ queue_adapter.perform_enqueued_jobs = old_perform_enqueued_jobs
+ queue_adapter.perform_enqueued_at_jobs = old_perform_enqueued_at_jobs
+ queue_adapter.filter = old_filter
end
+ end
- delegate :enqueued_jobs, :enqueued_jobs=,
- :performed_jobs, :performed_jobs=,
- to: :queue_adapter
+ def queue_adapter
+ ActiveJob::Base.queue_adapter
+ end
- private
- def clear_enqueued_jobs # :nodoc:
- enqueued_jobs.clear
- end
+ private
+ def clear_enqueued_jobs # :nodoc:
+ enqueued_jobs.clear
+ end
- def clear_performed_jobs # :nodoc:
- performed_jobs.clear
- end
+ def clear_performed_jobs # :nodoc:
+ performed_jobs.clear
+ end
- def enqueued_jobs_size(only: nil) # :nodoc:
- if only
- enqueued_jobs.count { |job| Array(only).include?(job.fetch(:job)) }
- else
- enqueued_jobs.count
- end
+ def enqueued_jobs_size(only: nil) # :nodoc:
+ if only
+ enqueued_jobs.count { |job| Array(only).include?(job.fetch(:job)) }
+ else
+ enqueued_jobs.count
end
+ end
- def serialize_args_for_assertion(args) # :nodoc:
- args.dup.tap do |serialized_args|
- serialized_args[:args] = ActiveJob::Arguments.serialize(serialized_args[:args]) if serialized_args[:args]
- serialized_args[:at] = serialized_args[:at].to_f if serialized_args[:at]
- end
+ def serialize_args_for_assertion(args) # :nodoc:
+ args.dup.tap do |serialized_args|
+ serialized_args[:args] = ActiveJob::Arguments.serialize(serialized_args[:args]) if serialized_args[:args]
+ serialized_args[:at] = serialized_args[:at].to_f if serialized_args[:at]
end
+ end
- def instantiate_job(payload) # :nodoc:
- job = payload[:job].new(*payload[:args])
- job.scheduled_at = Time.at(payload[:at]) if payload.key?(:at)
- job.queue_name = payload[:queue]
- job
- end
- end
+ def instantiate_job(payload) # :nodoc:
+ job = payload[:job].new(*payload[:args])
+ job.scheduled_at = Time.at(payload[:at]) if payload.key?(:at)
+ job.queue_name = payload[:queue]
+ job
+ end
end
end
diff --git a/activemodel/CHANGELOG.md b/activemodel/CHANGELOG.md
index 318e507ff1..fb7ab5cb40 100644
--- a/activemodel/CHANGELOG.md
+++ b/activemodel/CHANGELOG.md
@@ -1,3 +1,8 @@
+## Rails 5.0.0.beta3 (February 24, 2016) ##
+
+* No changes.
+
+
## Rails 5.0.0.beta2 (February 01, 2016) ##
* No changes.
diff --git a/activemodel/lib/active_model/gem_version.rb b/activemodel/lib/active_model/gem_version.rb
index 94514a0657..62862aa4e9 100644
--- a/activemodel/lib/active_model/gem_version.rb
+++ b/activemodel/lib/active_model/gem_version.rb
@@ -8,7 +8,7 @@ module ActiveModel
MAJOR = 5
MINOR = 0
TINY = 0
- PRE = "beta2"
+ PRE = "beta3"
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
end
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index c18403865f..c1a8803457 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,5 @@
+## Rails 5.0.0.beta3 (February 24, 2016) ##
+
* Ensure that mutations of the array returned from `ActiveRecord::Relation#to_a`
do not affect the original relation, by returning a duplicate array each time.
@@ -1452,18 +1454,6 @@
*Chris Sinjakli*
-* Validation errors would be raised for parent records when an association
- was saved when the parent had `validate: false`. It should not be the
- responsibility of the model to validate an associated object unless the
- object was created or modified by the parent.
-
- This fixes the issue by skipping validations if the parent record is
- persisted, not changed, and not marked for destruction.
-
- Fixes #17621.
-
- *Eileen M. Uchitelle*, *Aaron Patterson*
-
* Fix n+1 query problem when eager loading nil associations (fixes #18312)
*Sammy Larbi*
diff --git a/activerecord/lib/active_record/gem_version.rb b/activerecord/lib/active_record/gem_version.rb
index aa1f5c4fb4..73be4cb271 100644
--- a/activerecord/lib/active_record/gem_version.rb
+++ b/activerecord/lib/active_record/gem_version.rb
@@ -8,7 +8,7 @@ module ActiveRecord
MAJOR = 5
MINOR = 0
TINY = 0
- PRE = "beta2"
+ PRE = "beta3"
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
end
diff --git a/activerecord/lib/active_record/nested_attributes.rb b/activerecord/lib/active_record/nested_attributes.rb
index 0d5a8e6f25..ae78ceee01 100644
--- a/activerecord/lib/active_record/nested_attributes.rb
+++ b/activerecord/lib/active_record/nested_attributes.rb
@@ -195,15 +195,23 @@ module ActiveRecord
# Nested attributes for an associated collection can also be passed in
# the form of a hash of hashes instead of an array of hashes:
#
- # Member.create(name: 'joe',
- # posts_attributes: { first: { title: 'Foo' },
- # second: { title: 'Bar' } })
+ # Member.create(
+ # name: 'joe',
+ # posts_attributes: {
+ # first: { title: 'Foo' },
+ # second: { title: 'Bar' }
+ # }
+ # )
#
# has the same effect as
#
- # Member.create(name: 'joe',
- # posts_attributes: [ { title: 'Foo' },
- # { title: 'Bar' } ])
+ # Member.create(
+ # name: 'joe',
+ # posts_attributes: [
+ # { title: 'Foo' },
+ # { title: 'Bar' }
+ # ]
+ # )
#
# The keys of the hash which is the value for +:posts_attributes+ are
# ignored in this case.
diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb
index 4566aeb45b..6a6250eec3 100644
--- a/activerecord/test/cases/migration_test.rb
+++ b/activerecord/test/cases/migration_test.rb
@@ -516,13 +516,12 @@ class MigrationTest < ActiveRecord::TestCase
data_column = columns.detect { |c| c.name == "data" }
assert_nil data_column.default
-
+ ensure
Person.connection.drop_table :binary_testings, if_exists: true
end
unless mysql_enforcing_gtid_consistency?
def test_create_table_with_query
- Person.connection.drop_table :table_from_query_testings rescue nil
Person.connection.create_table(:person, force: true)
Person.connection.create_table :table_from_query_testings, as: "SELECT id FROM person"
@@ -530,12 +529,11 @@ class MigrationTest < ActiveRecord::TestCase
columns = Person.connection.columns(:table_from_query_testings)
assert_equal 1, columns.length
assert_equal "id", columns.first.name
-
+ ensure
Person.connection.drop_table :table_from_query_testings rescue nil
end
def test_create_table_with_query_from_relation
- Person.connection.drop_table :table_from_query_testings rescue nil
Person.connection.create_table(:person, force: true)
Person.connection.create_table :table_from_query_testings, as: Person.select(:id)
@@ -543,7 +541,7 @@ class MigrationTest < ActiveRecord::TestCase
columns = Person.connection.columns(:table_from_query_testings)
assert_equal 1, columns.length
assert_equal "id", columns.first.name
-
+ ensure
Person.connection.drop_table :table_from_query_testings rescue nil
end
end
@@ -586,9 +584,7 @@ class MigrationTest < ActiveRecord::TestCase
end
if current_adapter?(:Mysql2Adapter, :PostgreSQLAdapter)
- def test_out_of_range_limit_should_raise
- Person.connection.drop_table :test_integer_limits, if_exists: true
-
+ def test_out_of_range_integer_limit_should_raise
e = assert_raise(ActiveRecord::ActiveRecordError, "integer limit didn't raise") do
Person.connection.create_table :test_integer_limits, :force => true do |t|
t.column :bigone, :integer, :limit => 10
@@ -596,16 +592,22 @@ class MigrationTest < ActiveRecord::TestCase
end
assert_match(/No integer type has byte size 10/, e.message)
+ ensure
+ Person.connection.drop_table :test_integer_limits, if_exists: true
+ end
+ end
- unless current_adapter?(:PostgreSQLAdapter)
- assert_raise(ActiveRecord::ActiveRecordError, "text limit didn't raise") do
- Person.connection.create_table :test_text_limits, :force => true do |t|
- t.column :bigtext, :text, :limit => 0xfffffffff
- end
+ if current_adapter?(:Mysql2Adapter)
+ def test_out_of_range_text_limit_should_raise
+ e = assert_raise(ActiveRecord::ActiveRecordError, "text limit didn't raise") do
+ Person.connection.create_table :test_text_limits, force: true do |t|
+ t.text :bigtext, limit: 0xfffffffff
end
end
+
+ assert_match(/No text type has byte length #{0xfffffffff}/, e.message)
ensure
- Person.connection.drop_table :test_integer_limits, if_exists: true
+ Person.connection.drop_table :test_text_limits, if_exists: true
end
end
@@ -727,7 +729,7 @@ class ReservedWordsMigrationTest < ActiveRecord::TestCase
connection.add_index :values, :value
connection.remove_index :values, :column => :value
end
-
+ ensure
connection.drop_table :values rescue nil
end
end
@@ -743,7 +745,7 @@ class ExplicitlyNamedIndexMigrationTest < ActiveRecord::TestCase
connection.add_index :values, :value, name: 'a_different_name'
connection.remove_index :values, column: :value, name: 'a_different_name'
end
-
+ ensure
connection.drop_table :values rescue nil
end
end
diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md
index 2a5d203813..1a169d36be 100644
--- a/activesupport/CHANGELOG.md
+++ b/activesupport/CHANGELOG.md
@@ -1,3 +1,5 @@
+## Rails 5.0.0.beta3 (February 24, 2016) ##
+
* Deprecate arguments on `assert_nothing_raised`.
`assert_nothing_raised` does not assert the arguments that have been passed
diff --git a/activesupport/lib/active_support/deprecation/reporting.rb b/activesupport/lib/active_support/deprecation/reporting.rb
index f89fc0fe14..35f084dd7a 100644
--- a/activesupport/lib/active_support/deprecation/reporting.rb
+++ b/activesupport/lib/active_support/deprecation/reporting.rb
@@ -1,3 +1,5 @@
+require 'rbconfig'
+
module ActiveSupport
class Deprecation
module Reporting
@@ -81,17 +83,17 @@ module ActiveSupport
def extract_callstack(callstack)
return _extract_callstack(callstack) if callstack.first.is_a? String
- rails_gem_root = File.expand_path("../../../../..", __FILE__) + "/"
offending_line = callstack.find { |frame|
- frame.absolute_path && !frame.absolute_path.start_with?(rails_gem_root)
+ frame.absolute_path && !ignored_callstack(frame.absolute_path)
} || callstack.first
+
[offending_line.path, offending_line.lineno, offending_line.label]
end
def _extract_callstack(callstack)
warn "Please pass `caller_locations` to the deprecation API" if $VERBOSE
- rails_gem_root = File.expand_path("../../../../..", __FILE__) + "/"
- offending_line = callstack.find { |line| !line.start_with?(rails_gem_root) } || callstack.first
+ offending_line = callstack.find { |line| !ignored_callstack(line) } || callstack.first
+
if offending_line
if md = offending_line.match(/^(.+?):(\d+)(?::in `(.*?)')?/)
md.captures
@@ -100,6 +102,12 @@ module ActiveSupport
end
end
end
+
+ RAILS_GEM_ROOT = File.expand_path("../../../../..", __FILE__) + "/"
+
+ def ignored_callstack(path)
+ path.start_with?(RAILS_GEM_ROOT) || path.start_with?(RbConfig::CONFIG['rubylibdir'])
+ end
end
end
end
diff --git a/activesupport/lib/active_support/gem_version.rb b/activesupport/lib/active_support/gem_version.rb
index fc08273b6d..4166ffc2fb 100644
--- a/activesupport/lib/active_support/gem_version.rb
+++ b/activesupport/lib/active_support/gem_version.rb
@@ -8,7 +8,7 @@ module ActiveSupport
MAJOR = 5
MINOR = 0
TINY = 0
- PRE = "beta2"
+ PRE = "beta3"
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
end
diff --git a/activesupport/lib/active_support/logger.rb b/activesupport/lib/active_support/logger.rb
index 7626b28108..de48e717b6 100644
--- a/activesupport/lib/active_support/logger.rb
+++ b/activesupport/lib/active_support/logger.rb
@@ -1,8 +1,10 @@
require 'active_support/logger_silence'
+require 'active_support/logger_thread_safe_level'
require 'logger'
module ActiveSupport
class Logger < ::Logger
+ include ActiveSupport::LoggerThreadSafeLevel
include LoggerSilence
# Returns true if the logger destination matches one of the sources
@@ -48,6 +50,11 @@ module ActiveSupport
logger.level = level
super(level)
end
+
+ define_method(:local_level=) do |level|
+ logger.local_level = level if logger.respond_to?(:local_level=)
+ super(level) if respond_to?(:local_level=)
+ end
end
end
diff --git a/activesupport/lib/active_support/logger_silence.rb b/activesupport/lib/active_support/logger_silence.rb
index 125d81d973..3eb8098c77 100644
--- a/activesupport/lib/active_support/logger_silence.rb
+++ b/activesupport/lib/active_support/logger_silence.rb
@@ -7,39 +7,22 @@ module LoggerSilence
included do
cattr_accessor :silencer
- attr_reader :local_levels
self.silencer = true
end
- def after_initialize
- @local_levels = Concurrent::Map.new(:initial_capacity => 2)
- end
-
- def local_log_id
- Thread.current.__id__
- end
-
- def level
- local_levels[local_log_id] || super
- end
-
# Silences the logger for the duration of the block.
def silence(temporary_level = Logger::ERROR)
if silencer
begin
- old_local_level = local_levels[local_log_id]
- local_levels[local_log_id] = temporary_level
+ old_local_level = local_level
+ self.local_level = temporary_level
yield self
ensure
- if old_local_level
- local_levels[local_log_id] = old_local_level
- else
- local_levels.delete(local_log_id)
- end
+ self.local_level = old_local_level
end
else
yield self
end
end
-end \ No newline at end of file
+end
diff --git a/activesupport/lib/active_support/logger_thread_safe_level.rb b/activesupport/lib/active_support/logger_thread_safe_level.rb
new file mode 100644
index 0000000000..5fedb5e689
--- /dev/null
+++ b/activesupport/lib/active_support/logger_thread_safe_level.rb
@@ -0,0 +1,31 @@
+require 'active_support/concern'
+
+module ActiveSupport
+ module LoggerThreadSafeLevel # :nodoc:
+ extend ActiveSupport::Concern
+
+ def after_initialize
+ @local_levels = Concurrent::Map.new(initial_capacity: 2)
+ end
+
+ def local_log_id
+ Thread.current.__id__
+ end
+
+ def local_level
+ @local_levels[local_log_id]
+ end
+
+ def local_level=(level)
+ if level
+ @local_levels[local_log_id] = level
+ else
+ @local_levels.delete(local_log_id)
+ end
+ end
+
+ def level
+ local_level || super
+ end
+ end
+end
diff --git a/activesupport/lib/active_support/test_case.rb b/activesupport/lib/active_support/test_case.rb
index 2d2e25c970..1fc12d0bc1 100644
--- a/activesupport/lib/active_support/test_case.rb
+++ b/activesupport/lib/active_support/test_case.rb
@@ -76,8 +76,9 @@ module ActiveSupport
# end
def assert_nothing_raised(*args)
if args.present?
- ActiveSupport::Deprecation.warn("Passing arguments to assert_nothing_raised
- is deprecated and will be removed in Rails 5.1.")
+ ActiveSupport::Deprecation.warn(
+ "Passing arguments to assert_nothing_raised " \
+ "is deprecated and will be removed in Rails 5.1.")
end
yield
end
diff --git a/activesupport/test/logger_test.rb b/activesupport/test/logger_test.rb
index 317e09b7f2..5a91420f1e 100644
--- a/activesupport/test/logger_test.rb
+++ b/activesupport/test/logger_test.rb
@@ -141,6 +141,50 @@ class LoggerTest < ActiveSupport::TestCase
assert @output.string.include?("THIS IS HERE")
end
+ def test_logger_silencing_works_for_broadcast
+ another_output = StringIO.new
+ another_logger = Logger.new(another_output)
+
+ @logger.extend Logger.broadcast(another_logger)
+
+ @logger.debug "CORRECT DEBUG"
+ @logger.silence do
+ @logger.debug "FAILURE"
+ @logger.error "CORRECT ERROR"
+ end
+
+ assert @output.string.include?("CORRECT DEBUG")
+ assert @output.string.include?("CORRECT ERROR")
+ assert_not @output.string.include?("FAILURE")
+
+ assert another_output.string.include?("CORRECT DEBUG")
+ assert another_output.string.include?("CORRECT ERROR")
+ assert_not another_output.string.include?("FAILURE")
+ end
+
+ def test_broadcast_silencing_does_not_break_plain_ruby_logger
+ another_output = StringIO.new
+ another_logger = ::Logger.new(another_output)
+
+ @logger.extend Logger.broadcast(another_logger)
+
+ @logger.debug "CORRECT DEBUG"
+ @logger.silence do
+ @logger.debug "FAILURE"
+ @logger.error "CORRECT ERROR"
+ end
+
+ assert @output.string.include?("CORRECT DEBUG")
+ assert @output.string.include?("CORRECT ERROR")
+ assert_not @output.string.include?("FAILURE")
+
+ assert another_output.string.include?("CORRECT DEBUG")
+ assert another_output.string.include?("CORRECT ERROR")
+ assert another_output.string.include?("FAILURE")
+ # We can't silence plain ruby Logger cause with thread safety
+ # but at least we don't break it
+ end
+
def test_logger_level_per_object_thread_safety
logger1 = Logger.new(StringIO.new)
logger2 = Logger.new(StringIO.new)
diff --git a/guides/CHANGELOG.md b/guides/CHANGELOG.md
index d58016053b..d35d0f1976 100644
--- a/guides/CHANGELOG.md
+++ b/guides/CHANGELOG.md
@@ -1,3 +1,8 @@
+## Rails 5.0.0.beta3 (February 24, 2016) ##
+
+* No changes.
+
+
## Rails 5.0.0.beta2 (February 01, 2016) ##
* No changes.
diff --git a/guides/source/5_0_release_notes.md b/guides/source/5_0_release_notes.md
index f5abbd0cd4..91bca16356 100644
--- a/guides/source/5_0_release_notes.md
+++ b/guides/source/5_0_release_notes.md
@@ -316,6 +316,9 @@ Please refer to the [Changelog][action-mailer] for detailed changes.
* Template lookup now respects default locale and I18n fallbacks.
([commit](https://github.com/rails/rails/commit/ecb1981b))
+* Template can use fragment cache like Action View template.
+ ([Pull Request](https://github.com/rails/rails/pull/22825))
+
* Added `_mailer` suffix to mailers created via generator, following the same
naming convention used in controllers and jobs.
([Pull Request](https://github.com/rails/rails/pull/18074))
@@ -327,6 +330,9 @@ Please refer to the [Changelog][action-mailer] for detailed changes.
the mailer queue name.
([Pull Request](https://github.com/rails/rails/pull/18587))
+* Added `config.action_mailer.perform_caching` configuration to determine whether your templates should perform caching or not.
+ ([Pull Request](https://github.com/rails/rails/pull/22825))
+
Active Record
-------------
diff --git a/guides/source/action_mailer_basics.md b/guides/source/action_mailer_basics.md
index 91ea4efb55..558c16f5b0 100644
--- a/guides/source/action_mailer_basics.md
+++ b/guides/source/action_mailer_basics.md
@@ -407,6 +407,22 @@ use the rendered text for the text part. The render command is the same one used
inside of Action Controller, so you can use all the same options, such as
`:text`, `:inline` etc.
+#### Caching mailer view
+
+You can do cache in mailer views like in application views using `cache` method.
+
+```
+<% cache do %>
+ <%= @company.name %>
+<% end %>
+```
+
+And in order to use this feature, you need to configure your application with this:
+
+```
+ config.action_mailer.perform_caching = true
+```
+
### Action Mailer Layouts
Just like controller views, you can also have mailer layouts. The layout name
diff --git a/guides/source/action_view_overview.md b/guides/source/action_view_overview.md
index 5e6eae1071..29e0943741 100644
--- a/guides/source/action_view_overview.md
+++ b/guides/source/action_view_overview.md
@@ -599,7 +599,7 @@ This would add something like "Process data files (0.34523)" to the log, which y
#### cache
-A method for caching fragments of a view rather than an entire action or page. This technique is useful for caching pieces like menus, lists of news topics, static HTML fragments, and so on. This method takes a block that contains the content you wish to cache. See `ActionController::Caching::Fragments` for more information.
+A method for caching fragments of a view rather than an entire action or page. This technique is useful for caching pieces like menus, lists of news topics, static HTML fragments, and so on. This method takes a block that contains the content you wish to cache. See `AbstractController::Caching::Fragments` for more information.
```erb
<% cache do %>
diff --git a/guides/source/asset_pipeline.md b/guides/source/asset_pipeline.md
index 5dd54bf8ad..b6c612794c 100644
--- a/guides/source/asset_pipeline.md
+++ b/guides/source/asset_pipeline.md
@@ -335,8 +335,8 @@ include the 'data-turbolinks-track' option which causes turbolinks to check if
an asset has been updated and if so loads it into the page:
```erb
-<%= stylesheet_link_tag "application", media: "all", "data-turbolinks-track" => true %>
-<%= javascript_include_tag "application", "data-turbolinks-track" => true %>
+<%= stylesheet_link_tag "application", media: "all", "data-turbolinks-track" => "reload" %>
+<%= javascript_include_tag "application", "data-turbolinks-track" => "reload" %>
```
In regular views you can access images in the `public/assets/images` directory
diff --git a/guides/source/configuring.md b/guides/source/configuring.md
index a5fb396f15..23866b1800 100644
--- a/guides/source/configuring.md
+++ b/guides/source/configuring.md
@@ -531,6 +531,9 @@ There are a number of settings available on `config.action_mailer`:
* `config.action_mailer.deliver_later_queue_name` specifies the queue name for
mailers. By default this is `mailers`.
+* `config.action_mailer.perform_caching` specifies whether the mailer templates should perform fragment caching or not. By default this is false in all environments.
+
+
### Configuring Active Support
There are a few configuration options available in Active Support:
diff --git a/guides/source/form_helpers.md b/guides/source/form_helpers.md
index 2a289dd33a..422bc647ef 100644
--- a/guides/source/form_helpers.md
+++ b/guides/source/form_helpers.md
@@ -317,7 +317,7 @@ The Article model is directly available to users of the application, so - follow
resources :articles
```
-TIP: Declaring a resource has a number of side-affects. See [Rails Routing From the Outside In](routing.html#resource-routing-the-rails-default) for more information on setting up and using resources.
+TIP: Declaring a resource has a number of side effects. See [Rails Routing From the Outside In](routing.html#resource-routing-the-rails-default) for more information on setting up and using resources.
When dealing with RESTful resources, calls to `form_for` can get significantly easier if you rely on **record identification**. In short, you can just pass the model instance and have Rails figure out model name and the rest:
diff --git a/guides/source/rails_application_templates.md b/guides/source/rails_application_templates.md
index 5a46baff2d..3bb5d3c8a6 100644
--- a/guides/source/rails_application_templates.md
+++ b/guides/source/rails_application_templates.md
@@ -22,7 +22,7 @@ $ rails new blog -m ~/template.rb
$ rails new blog -m http://example.com/template.rb
```
-You can use the rake task `rails:template` to apply templates to an existing Rails application. The location of the template needs to be passed in to an environment variable named LOCATION. Again, this can either be path to a file or a URL.
+You can use the task `rails:template` to apply templates to an existing Rails application. The location of the template needs to be passed in to an environment variable named LOCATION. Again, this can either be path to a file or a URL.
```bash
$ bin/rails rails:template LOCATION=~/template.rb
@@ -38,7 +38,7 @@ The Rails templates API is easy to understand. Here's an example of a typical Ra
# template.rb
generate(:scaffold, "person name:string")
route "root to: 'people#index'"
-rake("db:migrate")
+rails_command("db:migrate")
after_bundle do
git :init
@@ -175,18 +175,24 @@ Executes an arbitrary command. Just like the backticks. Let's say you want to re
run "rm README.rdoc"
```
-### rake(command, options = {})
+### rails_command(command, options = {})
-Runs the supplied rake tasks in the Rails application. Let's say you want to migrate the database:
+Runs the supplied task in the Rails application. Let's say you want to migrate the database:
```ruby
-rake "db:migrate"
+rails_command "db:migrate"
```
-You can also run rake tasks with a different Rails environment:
+You can also run tasks with a different Rails environment:
```ruby
-rake "db:migrate", env: 'production'
+rails_command "db:migrate", env: 'production'
+```
+
+You can also run tasks as a super-user:
+
+```ruby
+rails_command "log:clear", sudo: true
```
### route(routing_code)
@@ -226,7 +232,7 @@ CODE
These methods let you ask questions from templates and decide the flow based on the user's answer. Let's say you want to Freeze Rails only if the user wants to:
```ruby
-rake("rails:freeze:gems") if yes?("Freeze rails gems?")
+rails_command("rails:freeze:gems") if yes?("Freeze rails gems?")
# no?(question) acts just the opposite.
```
diff --git a/guides/source/working_with_javascript_in_rails.md b/guides/source/working_with_javascript_in_rails.md
index 26ff5da7a3..c58aee96db 100644
--- a/guides/source/working_with_javascript_in_rails.md
+++ b/guides/source/working_with_javascript_in_rails.md
@@ -350,8 +350,8 @@ $("<%= escape_javascript(render @user) %>").appendTo("#users");
Turbolinks
----------
-Rails 4 ships with the [Turbolinks gem](https://github.com/turbolinks/turbolinks).
-This gem uses Ajax to speed up page rendering in most applications.
+Rails ships with the [Turbolinks library](https://github.com/turbolinks/turbolinks),
+which uses Ajax to speed up page rendering in most applications.
### How Turbolinks Works
@@ -364,14 +364,14 @@ will then use PushState to change the URL to the correct one, preserving
refresh semantics and giving you pretty URLs.
The only thing you have to do to enable Turbolinks is have it in your Gemfile,
-and put `//= require turbolinks` in your CoffeeScript manifest, which is usually
+and put `//= require turbolinks` in your JavaScript manifest, which is usually
`app/assets/javascripts/application.js`.
-If you want to disable Turbolinks for certain links, add a `data-no-turbolink`
+If you want to disable Turbolinks for certain links, add a `data-turbolinks="false"`
attribute to the tag:
```html
-<a href="..." data-no-turbolink>No turbolinks here</a>.
+<a href="..." data-turbolinks="false">No turbolinks here</a>.
```
### Page Change Events
@@ -389,7 +389,7 @@ event that this relies on will not be fired. If you have code that looks like
this, you must change your code to do this instead:
```coffeescript
-$(document).on "page:change", ->
+$(document).on "turbolinks:load", ->
alert "page has loaded!"
```
diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md
index a3be5356a1..40140c49f6 100644
--- a/railties/CHANGELOG.md
+++ b/railties/CHANGELOG.md
@@ -1,3 +1,15 @@
+## Rails 5.0.0.beta3 (February 24, 2016) ##
+
+* Alias `rake` with `rails_command` in the Rails Application Templates API
+ following Rails 5 convention of preferring "rails" to "rake" to run tasks.
+
+ *claudiob*
+
+* Generate applications with an option to log to STDOUT in production
+ using the environment variable `RAILS_LOG_TO_STDOUT`.
+
+ *Richard Schneeman*
+
* Change fail fast of `bin/rails test` interrupts run on error.
*Yuji Yaginuma*
diff --git a/railties/lib/rails/gem_version.rb b/railties/lib/rails/gem_version.rb
index 93e0151602..081222425c 100644
--- a/railties/lib/rails/gem_version.rb
+++ b/railties/lib/rails/gem_version.rb
@@ -8,7 +8,7 @@ module Rails
MAJOR = 5
MINOR = 0
TINY = 0
- PRE = "beta2"
+ PRE = "beta3"
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
end
diff --git a/railties/lib/rails/generators/actions.rb b/railties/lib/rails/generators/actions.rb
index 9ca731347a..5fa487b78e 100644
--- a/railties/lib/rails/generators/actions.rb
+++ b/railties/lib/rails/generators/actions.rb
@@ -216,8 +216,9 @@ module Rails
log :rake, command
env = options[:env] || ENV["RAILS_ENV"] || 'development'
sudo = options[:sudo] && RbConfig::CONFIG['host_os'] !~ /mswin|mingw/ ? 'sudo ' : ''
- in_root { run("#{sudo}#{extify(:rake)} #{command} RAILS_ENV=#{env}", verbose: false) }
+ in_root { run("#{sudo}#{extify(:rails)} #{command} RAILS_ENV=#{env}", verbose: false) }
end
+ alias :rails_command :rake
# Just run the capify command in root
#
diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb
index 9adfcc6ee7..ed4e73fb90 100644
--- a/railties/lib/rails/generators/app_base.rb
+++ b/railties/lib/rails/generators/app_base.rb
@@ -311,12 +311,7 @@ module Rails
end
def coffee_gemfile_entry
- comment = 'Use CoffeeScript for .coffee assets and views'
- if options.dev? || options.edge?
- GemfileEntry.github 'coffee-rails', 'rails/coffee-rails', nil, comment
- else
- GemfileEntry.version 'coffee-rails', '~> 4.1.0', comment
- end
+ GemfileEntry.version 'coffee-rails', '~> 4.1.0', 'Use CoffeeScript for .coffee assets and views'
end
def javascript_gemfile_entry
@@ -328,8 +323,8 @@ module Rails
"Use #{options[:javascript]} as the JavaScript library")
unless options[:skip_turbolinks]
- gems << GemfileEntry.version("turbolinks", nil,
- "Turbolinks makes following links in your web application faster. Read more: https://github.com/turbolinks/turbolinks")
+ gems << GemfileEntry.version("turbolinks", "~> 5.x",
+ "Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks")
end
gems
diff --git a/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt b/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt
index 68b5c051b2..ec781721cb 100644
--- a/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt
+++ b/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt
@@ -11,8 +11,8 @@
<%%= stylesheet_link_tag 'application', media: 'all' %>
<%- else -%>
<%- if gemfile_entries.any? { |m| m.name == 'turbolinks' } -%>
- <%%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
- <%%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
+ <%%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => 'reload' %>
+ <%%= javascript_include_tag 'application', 'data-turbolinks-track' => 'reload' %>
<%- else -%>
<%%= stylesheet_link_tag 'application', media: 'all' %>
<%%= javascript_include_tag 'application' %>
diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt
index d4e2b1c756..e6a2de0928 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt
+++ b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt
@@ -15,18 +15,22 @@ Rails.application.configure do
# Enable/disable caching. By default caching is disabled.
if Rails.root.join('tmp/caching-dev.txt').exist?
config.action_controller.perform_caching = true
+
config.cache_store = :memory_store
config.public_file_server.headers = {
'Cache-Control' => 'public, max-age=172800'
}
else
config.action_controller.perform_caching = false
+
config.cache_store = :null_store
end
<%- unless options.skip_action_mailer? -%>
# Don't care if the mailer can't send.
config.action_mailer.raise_delivery_errors = false
+
+ config.action_mailer.perform_caching = false
<%- end -%>
# Print deprecation notices to the Rails logger.
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 e14e2c7286..236e42fcd7 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
@@ -71,6 +71,7 @@ Rails.application.configure do
# config.active_job.queue_adapter = :resque
# config.active_job.queue_name_prefix = "<%= app_name %>_#{Rails.env}"
<%- unless options.skip_action_mailer? -%>
+ config.action_mailer.perform_caching = false
# Ignore bad email addresses and do not raise email delivery errors.
# Set this to true and configure the email server for immediate delivery to raise delivery errors.
diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt
index e8c8b00669..42fee3b036 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt
+++ b/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt
@@ -28,6 +28,7 @@ Rails.application.configure do
# Disable request forgery protection in test environment.
config.action_controller.allow_forgery_protection = false
<%- unless options.skip_action_mailer? -%>
+ config.action_mailer.perform_caching = false
# Tell Action Mailer not to deliver emails to the real world.
# The :test delivery method accumulates sent emails in the
diff --git a/railties/lib/rails/generators/rails/app/templates/config/puma.rb b/railties/lib/rails/generators/rails/app/templates/config/puma.rb
index 1bf274bc66..c7f311f811 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/puma.rb
+++ b/railties/lib/rails/generators/rails/app/templates/config/puma.rb
@@ -42,3 +42,6 @@ environment ENV.fetch("RAILS_ENV") { "development" }
# on_worker_boot do
# ActiveRecord::Base.establish_connection if defined?(ActiveRecord)
# end
+
+# Allow puma to be restarted by `rails restart` command.
+plugin :tmp_restart
diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb
index 1c7d1e1f5f..d03dd1afcc 100644
--- a/railties/test/application/configuration_test.rb
+++ b/railties/test/application/configuration_test.rb
@@ -999,7 +999,7 @@ module ApplicationTests
app 'development'
post "/posts.json", '{ "title": "foo", "name": "bar" }', "CONTENT_TYPE" => "application/json"
- assert_equal '<ActionController::Parameters {"title"=>"foo"}>', last_response.body
+ assert_equal '<ActionController::Parameters {"title"=>"foo"} permitted: false>', last_response.body
end
test "config.action_controller.permit_all_parameters = true" do
diff --git a/railties/test/generators/actions_test.rb b/railties/test/generators/actions_test.rb
index 3300850604..6158748194 100644
--- a/railties/test/generators/actions_test.rb
+++ b/railties/test/generators/actions_test.rb
@@ -202,7 +202,7 @@ class ActionsTest < Rails::Generators::TestCase
end
def test_rake_should_run_rake_command_with_default_env
- assert_called_with(generator, :run, ["rake log:clear RAILS_ENV=development", verbose: false]) do
+ assert_called_with(generator, :run, ["rails log:clear RAILS_ENV=development", verbose: false]) do
with_rails_env nil do
action :rake, 'log:clear'
end
@@ -210,13 +210,13 @@ class ActionsTest < Rails::Generators::TestCase
end
def test_rake_with_env_option_should_run_rake_command_in_env
- assert_called_with(generator, :run, ['rake log:clear RAILS_ENV=production', verbose: false]) do
+ assert_called_with(generator, :run, ['rails log:clear RAILS_ENV=production', verbose: false]) do
action :rake, 'log:clear', env: 'production'
end
end
def test_rake_with_rails_env_variable_should_run_rake_command_in_env
- assert_called_with(generator, :run, ['rake log:clear RAILS_ENV=production', verbose: false]) do
+ assert_called_with(generator, :run, ['rails log:clear RAILS_ENV=production', verbose: false]) do
with_rails_env "production" do
action :rake, 'log:clear'
end
@@ -224,7 +224,7 @@ class ActionsTest < Rails::Generators::TestCase
end
def test_env_option_should_win_over_rails_env_variable_when_running_rake
- assert_called_with(generator, :run, ['rake log:clear RAILS_ENV=production', verbose: false]) do
+ assert_called_with(generator, :run, ['rails log:clear RAILS_ENV=production', verbose: false]) do
with_rails_env "staging" do
action :rake, 'log:clear', env: 'production'
end
@@ -232,13 +232,51 @@ class ActionsTest < Rails::Generators::TestCase
end
def test_rake_with_sudo_option_should_run_rake_command_with_sudo
- assert_called_with(generator, :run, ["sudo rake log:clear RAILS_ENV=development", verbose: false]) do
+ assert_called_with(generator, :run, ["sudo rails log:clear RAILS_ENV=development", verbose: false]) do
with_rails_env nil do
action :rake, 'log:clear', sudo: true
end
end
end
+ def test_rails_command_should_run_rails_command_with_default_env
+ assert_called_with(generator, :run, ["rails log:clear RAILS_ENV=development", verbose: false]) do
+ with_rails_env nil do
+ action :rails_command, 'log:clear'
+ end
+ end
+ end
+
+ def test_rails_command_with_env_option_should_run_rails_command_in_env
+ assert_called_with(generator, :run, ['rails log:clear RAILS_ENV=production', verbose: false]) do
+ action :rails_command, 'log:clear', env: 'production'
+ end
+ end
+
+ def test_rails_command_with_rails_env_variable_should_run_rails_command_in_env
+ assert_called_with(generator, :run, ['rails log:clear RAILS_ENV=production', verbose: false]) do
+ with_rails_env "production" do
+ action :rails_command, 'log:clear'
+ end
+ end
+ end
+
+ def test_env_option_should_win_over_rails_env_variable_when_running_rails
+ assert_called_with(generator, :run, ['rails log:clear RAILS_ENV=production', verbose: false]) do
+ with_rails_env "staging" do
+ action :rails_command, 'log:clear', env: 'production'
+ end
+ end
+ end
+
+ def test_rails_command_with_sudo_option_should_run_rails_command_with_sudo
+ assert_called_with(generator, :run, ["sudo rails log:clear RAILS_ENV=development", verbose: false]) do
+ with_rails_env nil do
+ action :rails_command, 'log:clear', sudo: true
+ end
+ end
+ end
+
def test_capify_should_run_the_capify_command
assert_called_with(generator, :run, ['capify .', verbose: false]) do
action :capify!
diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb
index 921a5b36b5..c2c3638f07 100644
--- a/railties/test/generators/app_generator_test.rb
+++ b/railties/test/generators/app_generator_test.rb
@@ -64,8 +64,8 @@ class AppGeneratorTest < Rails::Generators::TestCase
def test_assets
run_generator
- assert_file("app/views/layouts/application.html.erb", /stylesheet_link_tag\s+'application', media: 'all', 'data-turbolinks-track' => true/)
- assert_file("app/views/layouts/application.html.erb", /javascript_include_tag\s+'application', 'data-turbolinks-track' => true/)
+ assert_file("app/views/layouts/application.html.erb", /stylesheet_link_tag\s+'application', media: 'all', 'data-turbolinks-track' => 'reload'/)
+ assert_file("app/views/layouts/application.html.erb", /javascript_include_tag\s+'application', 'data-turbolinks-track' => 'reload'/)
assert_file("app/assets/stylesheets/application.css")
assert_file("app/assets/javascripts/application.js")
end
diff --git a/version.rb b/version.rb
index 93e0151602..081222425c 100644
--- a/version.rb
+++ b/version.rb
@@ -8,7 +8,7 @@ module Rails
MAJOR = 5
MINOR = 0
TINY = 0
- PRE = "beta2"
+ PRE = "beta3"
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
end