aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Gemfile.lock206
-rw-r--r--actioncable/test/channel/base_test.rb12
-rw-r--r--actioncable/test/channel/broadcasting_test.rb15
-rw-r--r--actioncable/test/channel/periodic_timers_test.rb24
-rw-r--r--actioncable/test/channel/rejection_test.rb39
-rw-r--r--actioncable/test/channel/stream_test.rb45
-rw-r--r--actioncable/test/connection/client_socket_test.rb7
-rw-r--r--actioncable/test/connection/identifier_test.rb13
-rw-r--r--actioncable/test/connection/stream_test.rb10
-rw-r--r--actioncable/test/stubs/test_adapter.rb4
-rw-r--r--actioncable/test/stubs/test_connection.rb2
-rw-r--r--actioncable/test/test_helper.rb1
-rw-r--r--actionmailer/CHANGELOG.md8
-rw-r--r--actionmailer/lib/action_mailer/base.rb24
-rw-r--r--actionmailer/lib/action_mailer/preview.rb27
-rw-r--r--actionmailer/test/base_test.rb95
-rw-r--r--actionpack/lib/action_controller/metal/request_forgery_protection.rb2
-rw-r--r--actionpack/test/controller/request_forgery_protection_test.rb5
-rw-r--r--activerecord/CHANGELOG.md4
-rw-r--r--activestorage/app/models/active_storage/blob.rb10
-rw-r--r--activestorage/lib/active_storage/downloader.rb6
-rw-r--r--activestorage/test/models/blob_test.rb13
-rw-r--r--activesupport/CHANGELOG.md2
-rw-r--r--activesupport/lib/active_support/i18n_railtie.rb1
-rw-r--r--activesupport/lib/active_support/values/time_zone.rb9
-rw-r--r--activesupport/test/time_zone_test.rb10
26 files changed, 408 insertions, 186 deletions
diff --git a/Gemfile.lock b/Gemfile.lock
index 77c234814a..2fdd898943 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -96,52 +96,55 @@ PATH
GEM
remote: https://rubygems.org/
specs:
- activerecord-jdbc-adapter (1.3.24)
- activerecord (>= 2.2, < 5.0)
- activerecord-jdbcmysql-adapter (1.3.24)
- activerecord-jdbc-adapter (~> 1.3.24)
- jdbc-mysql (>= 5.1.22)
- activerecord-jdbcpostgresql-adapter (1.3.24)
- activerecord-jdbc-adapter (~> 1.3.24)
- jdbc-postgres (~> 9.1, <= 9.4.1206)
- activerecord-jdbcsqlite3-adapter (1.3.24)
- activerecord-jdbc-adapter (~> 1.3.24)
- jdbc-sqlite3 (>= 3.7.2, < 3.9)
+ activerecord-jdbc-adapter (51.1-java)
+ activerecord (~> 5.1.0)
+ activerecord-jdbcmysql-adapter (51.1-java)
+ activerecord-jdbc-adapter (= 51.1)
+ jdbc-mysql (~> 5.1.36)
+ activerecord-jdbcpostgresql-adapter (51.1-java)
+ activerecord-jdbc-adapter (= 51.1)
+ jdbc-postgres (>= 9.4, < 43)
+ activerecord-jdbcsqlite3-adapter (51.1-java)
+ activerecord-jdbc-adapter (= 51.1)
+ jdbc-sqlite3 (~> 3.8, < 3.30)
addressable (2.5.2)
public_suffix (>= 2.0.2, < 4.0)
- amq-protocol (2.2.0)
- archive-zip (0.7.0)
+ amq-protocol (2.3.0)
+ archive-zip (0.11.0)
io-like (~> 0.3.0)
ast (2.4.0)
- aws-partitions (1.20.0)
- aws-sdk-core (3.3.0)
+ aws-eventstream (1.0.0)
+ aws-partitions (1.88.0)
+ aws-sdk-core (3.21.2)
+ aws-eventstream (~> 1.0)
aws-partitions (~> 1.0)
aws-sigv4 (~> 1.0)
jmespath (~> 1.0)
- aws-sdk-kms (1.1.0)
+ aws-sdk-kms (1.5.0)
aws-sdk-core (~> 3)
aws-sigv4 (~> 1.0)
- aws-sdk-s3 (1.2.0)
- aws-sdk-core (~> 3)
+ aws-sdk-s3 (1.13.0)
+ aws-sdk-core (~> 3, >= 3.21.2)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.0)
- aws-sigv4 (1.0.1)
- azure-core (0.1.11)
+ aws-sigv4 (1.0.2)
+ azure-core (0.1.14)
faraday (~> 0.9)
faraday_middleware (~> 0.10)
nokogiri (~> 1.6)
- azure-storage (0.12.3.preview)
+ azure-storage (0.15.0.preview)
azure-core (~> 0.1)
faraday (~> 0.9)
faraday_middleware (~> 0.10)
+ nokogiri (~> 1.6, >= 1.6.8)
backburner (1.4.1)
beaneater (~> 1.0)
concurrent-ruby (~> 1.0.1)
dante (> 0.1.5)
- bcrypt (3.1.11)
- bcrypt (3.1.11-java)
- bcrypt (3.1.11-x64-mingw32)
- bcrypt (3.1.11-x86-mingw32)
+ bcrypt (3.1.12)
+ bcrypt (3.1.12-java)
+ bcrypt (3.1.12-x64-mingw32)
+ bcrypt (3.1.12-x86-mingw32)
beaneater (1.0.0)
benchmark-ips (2.7.2)
blade (0.7.1)
@@ -157,30 +160,30 @@ GEM
thor (>= 0.19.1)
useragent (~> 0.16.7)
blade-qunit_adapter (2.0.1)
- blade-sauce_labs_plugin (0.7.2)
+ blade-sauce_labs_plugin (0.7.3)
childprocess
faraday
selenium-webdriver
- bootsnap (1.2.1)
+ bootsnap (1.3.0)
msgpack (~> 1.0)
- bootsnap (1.2.1-java)
+ bootsnap (1.3.0-java)
msgpack (~> 1.0)
builder (3.2.3)
- bunny (2.6.6)
- amq-protocol (>= 2.1.0)
- byebug (9.0.6)
- capybara (3.0.1)
+ bunny (2.9.2)
+ amq-protocol (~> 2.3.0)
+ byebug (10.0.2)
+ capybara (3.1.1)
addressable
mini_mime (>= 0.1.3)
nokogiri (~> 1.8)
rack (>= 1.6.0)
rack-test (>= 0.6.3)
xpath (~> 3.0)
- childprocess (0.7.1)
+ childprocess (0.9.0)
ffi (~> 1.0, >= 1.0.11)
- chromedriver-helper (1.1.0)
- archive-zip (~> 0.7.0)
- nokogiri (~> 1.6)
+ chromedriver-helper (1.2.0)
+ archive-zip (~> 0.10)
+ nokogiri (~> 1.8)
coffee-rails (4.2.2)
coffee-script (>= 2.2.0)
railties (>= 4.0.0)
@@ -190,19 +193,19 @@ GEM
coffee-script-source (1.12.2)
concurrent-ruby (1.0.5)
concurrent-ruby (1.0.5-java)
- connection_pool (2.2.1)
+ connection_pool (2.2.2)
cookiejar (0.3.3)
- crass (1.0.3)
+ crass (1.0.4)
curses (1.0.2)
- daemons (1.2.4)
+ daemons (1.2.6)
dalli (2.7.8)
dante (0.2.0)
declarative (0.0.10)
declarative-option (0.1.0)
- delayed_job (4.1.4)
- activesupport (>= 3.0, < 5.2)
- delayed_job_active_record (4.1.2)
- activerecord (>= 3.0, < 5.2)
+ delayed_job (4.1.5)
+ activesupport (>= 3.0, < 5.3)
+ delayed_job_active_record (4.1.3)
+ activerecord (>= 3.0, < 5.3)
delayed_job (>= 3.0, < 5)
digest-crc (0.4.1)
em-http-request (1.1.5)
@@ -213,13 +216,13 @@ GEM
http_parser.rb (>= 0.6.0)
em-socksify (0.3.2)
eventmachine (>= 1.0.0.beta.4)
- erubi (1.7.0)
+ erubi (1.7.1)
et-orbi (1.1.2)
tzinfo
event_emitter (0.2.6)
- eventmachine (1.2.5)
+ eventmachine (1.2.7)
execjs (2.7.0)
- faraday (0.13.1)
+ faraday (0.15.2)
multipart-post (>= 1.2, < 3)
faraday_middleware (0.12.2)
faraday (>= 0.7.4, < 1.0)
@@ -238,6 +241,9 @@ GEM
ffi (1.9.21-java)
ffi (1.9.21-x64-mingw32)
ffi (1.9.21-x86-mingw32)
+ fugit (1.1.1)
+ et-orbi (~> 1.1, >= 1.1.1)
+ raabro (~> 1.1)
globalid (0.4.1)
activesupport (>= 4.2.0)
google-api-client (0.19.8)
@@ -251,7 +257,7 @@ GEM
google-cloud-env (~> 1.0)
google-cloud-env (1.0.1)
faraday (~> 0.11)
- google-cloud-storage (1.11.0)
+ google-cloud-storage (1.12.0)
digest-crc (~> 0.4)
google-api-client (~> 0.19.0)
google-cloud-core (~> 1.2)
@@ -268,23 +274,23 @@ GEM
hiredis (0.6.1-java)
http_parser.rb (0.6.0)
httpclient (2.8.3)
- i18n (1.0.0)
+ i18n (1.0.1)
concurrent-ruby (~> 1.0)
image_processing (1.2.0)
mini_magick (~> 4.0)
ruby-vips (>= 2.0.10, < 3)
io-like (0.3.0)
- jdbc-mysql (5.1.44)
- jdbc-postgres (9.4.1206)
- jdbc-sqlite3 (3.8.11.2)
- jmespath (1.3.1)
+ jdbc-mysql (5.1.46)
+ jdbc-postgres (42.1.4)
+ jdbc-sqlite3 (3.20.1)
+ jmespath (1.4.0)
json (2.1.0)
json (2.1.0-java)
jwt (2.1.0)
kindlerb (1.2.0)
mustache
nokogiri
- libxml-ruby (3.0.0)
+ libxml-ruby (3.1.0)
listen (3.1.5)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
@@ -293,12 +299,12 @@ GEM
logging (2.2.2)
little-plugger (~> 1.1)
multi_json (~> 1.10)
- loofah (2.2.1)
+ loofah (2.2.2)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
mail (2.7.0)
mini_mime (>= 0.1.1)
- marcel (0.3.1)
+ marcel (0.3.2)
mimemagic (~> 0.3.2)
memoist (0.16.0)
metaclass (0.0.4)
@@ -323,15 +329,15 @@ GEM
msgpack (1.2.4-java)
msgpack (1.2.4-x64-mingw32)
msgpack (1.2.4-x86-mingw32)
- multi_json (1.12.2)
+ multi_json (1.13.1)
multipart-post (2.0.0)
mustache (1.0.5)
mustermann (1.0.2)
- mysql2 (0.5.0)
- mysql2 (0.5.0-x64-mingw32)
- mysql2 (0.5.0-x86-mingw32)
- nio4r (2.2.0)
- nio4r (2.2.0-java)
+ mysql2 (0.5.1)
+ mysql2 (0.5.1-x64-mingw32)
+ mysql2 (0.5.1-x86-mingw32)
+ nio4r (2.3.1)
+ nio4r (2.3.1-java)
nokogiri (1.8.2)
mini_portile2 (~> 2.3.0)
nokogiri (1.8.2-java)
@@ -343,22 +349,23 @@ GEM
parallel (1.12.1)
parser (2.5.1.0)
ast (~> 2.4.0)
- path_expander (1.0.2)
+ path_expander (1.0.3)
pg (1.0.0)
pg (1.0.0-x64-mingw32)
pg (1.0.0-x86-mingw32)
powerpack (0.1.1)
psych (3.0.2)
public_suffix (3.0.2)
- puma (3.9.1)
- puma (3.9.1-java)
- que (0.14.0)
+ puma (3.11.4)
+ puma (3.11.4-java)
+ que (0.14.3)
qunit-selenium (0.0.4)
selenium-webdriver
thor
+ raabro (1.1.5)
racc (1.4.14)
- rack (2.0.4)
- rack-cache (1.7.0)
+ rack (2.0.5)
+ rack-cache (1.7.2)
rack (>= 0.4)
rack-protection (2.0.1)
rack
@@ -367,12 +374,12 @@ GEM
rails-dom-testing (2.0.3)
activesupport (>= 4.2.0)
nokogiri (>= 1.6)
- rails-html-sanitizer (1.0.3)
- loofah (~> 2.0)
+ rails-html-sanitizer (1.0.4)
+ loofah (~> 2.2, >= 2.2.2)
rainbow (3.0.0)
- rake (12.3.0)
- rb-fsevent (0.10.2)
- rdoc (6.0.1)
+ rake (12.3.1)
+ rb-fsevent (0.10.3)
+ rdoc (6.0.4)
redcarpet (3.2.3)
redis (4.0.1)
redis-namespace (1.6.0)
@@ -393,7 +400,7 @@ GEM
resque (~> 1.26)
rufus-scheduler (~> 3.2)
retriable (3.1.1)
- rubocop (0.54.0)
+ rubocop (0.56.0)
parallel (~> 1.10)
parser (>= 2.5)
powerpack (~> 0.1)
@@ -401,13 +408,13 @@ GEM
ruby-progressbar (~> 1.7)
unicode-display_width (~> 1.0, >= 1.0.1)
ruby-progressbar (1.9.0)
- ruby-vips (2.0.10)
+ ruby-vips (2.0.12)
ffi (~> 1.9)
ruby_dep (1.5.0)
rubyzip (1.2.1)
- rufus-scheduler (3.4.2)
- et-orbi (~> 1.0)
- sass (3.5.3)
+ rufus-scheduler (3.5.0)
+ fugit (~> 1.1, >= 1.1.1)
+ sass (3.5.6)
sass-listen (~> 4.0.0)
sass-listen (4.0.0)
rb-fsevent (~> 0.9, >= 0.9.4)
@@ -420,17 +427,17 @@ GEM
tilt (>= 1.1, < 3)
sdoc (1.0.0)
rdoc (>= 5.0)
- selenium-webdriver (3.5.1)
+ selenium-webdriver (3.12.0)
childprocess (~> 0.5)
- rubyzip (~> 1.0)
- sequel (4.49.0)
- serverengine (1.5.11)
+ rubyzip (~> 1.2)
+ sequel (5.8.0)
+ serverengine (2.0.6)
sigdump (~> 0.2.2)
- sidekiq (5.0.5)
+ sidekiq (5.1.3)
concurrent-ruby (~> 1.0)
connection_pool (~> 2.2, >= 2.2.0)
rack-protection (>= 1.5.0)
- redis (>= 3.3.4, < 5)
+ redis (>= 3.3.5, < 5)
sigdump (0.2.4)
signet (0.8.1)
addressable (~> 2.3)
@@ -442,30 +449,29 @@ GEM
rack (~> 2.0)
rack-protection (= 2.0.1)
tilt (~> 2.0)
- sneakers (2.5.0)
- bunny (~> 2.6.4)
- serverengine (~> 1.5.11)
+ sneakers (2.7.0)
+ bunny (~> 2.9.2)
+ concurrent-ruby (~> 1.0)
+ serverengine (~> 2.0.5)
thor
- thread (~> 0.1.7)
sprockets (3.7.1)
concurrent-ruby (~> 1.0)
rack (> 1, < 3)
sprockets-export (1.0.0)
- sprockets-rails (3.2.0)
+ sprockets-rails (3.2.1)
actionpack (>= 4.0)
activesupport (>= 4.0)
sprockets (>= 3.0.0)
sqlite3 (1.3.13)
sqlite3 (1.3.13-x64-mingw32)
sqlite3 (1.3.13-x86-mingw32)
- stackprof (0.2.10)
- sucker_punch (2.0.2)
+ stackprof (0.2.11)
+ sucker_punch (2.0.4)
concurrent-ruby (~> 1.0.0)
thin (1.7.2)
daemons (~> 1.0, >= 1.0.9)
eventmachine (~> 1.0, >= 1.0.4)
rack (>= 1, < 3)
- thread (0.1.7)
thread_safe (0.3.6)
thread_safe (0.3.6-java)
tilt (2.0.8)
@@ -474,26 +480,26 @@ GEM
turbolinks-source (5.1.0)
tzinfo (1.2.5)
thread_safe (~> 0.1)
- tzinfo-data (1.2017.2)
+ tzinfo-data (1.2018.5)
tzinfo (>= 1.0.0)
uber (0.1.0)
- uglifier (3.2.0)
+ uglifier (4.1.10)
execjs (>= 0.3.0, < 3)
- unicode-display_width (1.3.2)
- useragent (0.16.8)
+ unicode-display_width (1.3.3)
+ useragent (0.16.10)
vegas (0.1.11)
rack (>= 1.0.0)
w3c_validators (1.3.3)
json (>= 1.8)
nokogiri (~> 1.6)
wdm (0.1.1)
- websocket (1.2.4)
- websocket-driver (0.6.5)
+ websocket (1.2.8)
+ websocket-driver (0.7.0)
websocket-extensions (>= 0.1.0)
- websocket-driver (0.6.5-java)
+ websocket-driver (0.7.0-java)
websocket-extensions (>= 0.1.0)
- websocket-extensions (0.1.2)
- xpath (3.0.0)
+ websocket-extensions (0.1.3)
+ xpath (3.1.0)
nokogiri (~> 1.8)
PLATFORMS
diff --git a/actioncable/test/channel/base_test.rb b/actioncable/test/channel/base_test.rb
index 3b8eb63975..d368794f73 100644
--- a/actioncable/test/channel/base_test.rb
+++ b/actioncable/test/channel/base_test.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
require "test_helper"
+require "minitest/mock"
require "stubs/test_connection"
require "stubs/room"
@@ -226,12 +227,13 @@ class ActionCable::Channel::BaseTest < ActiveSupport::TestCase
events << ActiveSupport::Notifications::Event.new(*args)
end
- @channel.stubs(:subscription_confirmation_sent?).returns(false)
- @channel.send(:transmit_subscription_confirmation)
+ @channel.stub(:subscription_confirmation_sent?, false) do
+ @channel.send(:transmit_subscription_confirmation)
- assert_equal 1, events.length
- assert_equal "transmit_subscription_confirmation.action_cable", events[0].name
- assert_equal "ActionCable::Channel::BaseTest::ChatChannel", events[0].payload[:channel_class]
+ assert_equal 1, events.length
+ assert_equal "transmit_subscription_confirmation.action_cable", events[0].name
+ assert_equal "ActionCable::Channel::BaseTest::ChatChannel", events[0].payload[:channel_class]
+ end
ensure
ActiveSupport::Notifications.unsubscribe "transmit_subscription_confirmation.action_cable"
end
diff --git a/actioncable/test/channel/broadcasting_test.rb b/actioncable/test/channel/broadcasting_test.rb
index ab58f33511..f184147c51 100644
--- a/actioncable/test/channel/broadcasting_test.rb
+++ b/actioncable/test/channel/broadcasting_test.rb
@@ -1,10 +1,13 @@
# frozen_string_literal: true
require "test_helper"
+require "active_support/testing/method_call_assertions"
require "stubs/test_connection"
require "stubs/room"
class ActionCable::Channel::BroadcastingTest < ActiveSupport::TestCase
+ include ActiveSupport::Testing::MethodCallAssertions
+
class ChatChannel < ActionCable::Channel::Base
end
@@ -13,8 +16,16 @@ class ActionCable::Channel::BroadcastingTest < ActiveSupport::TestCase
end
test "broadcasts_to" do
- ActionCable.stubs(:server).returns mock().tap { |m| m.expects(:broadcast).with("action_cable:channel:broadcasting_test:chat:Room#1-Campfire", "Hello World") }
- ChatChannel.broadcast_to(Room.new(1), "Hello World")
+ assert_called_with(
+ ActionCable.server,
+ :broadcast,
+ [
+ "action_cable:channel:broadcasting_test:chat:Room#1-Campfire",
+ "Hello World"
+ ]
+ ) do
+ ChatChannel.broadcast_to(Room.new(1), "Hello World")
+ end
end
test "broadcasting_for with an object" do
diff --git a/actioncable/test/channel/periodic_timers_test.rb b/actioncable/test/channel/periodic_timers_test.rb
index 500b984ca6..8d9482577c 100644
--- a/actioncable/test/channel/periodic_timers_test.rb
+++ b/actioncable/test/channel/periodic_timers_test.rb
@@ -4,8 +4,11 @@ require "test_helper"
require "stubs/test_connection"
require "stubs/room"
require "active_support/time"
+require "active_support/testing/method_call_assertions"
class ActionCable::Channel::PeriodicTimersTest < ActiveSupport::TestCase
+ include ActiveSupport::Testing::MethodCallAssertions
+
class ChatChannel < ActionCable::Channel::Base
# Method name arg
periodically :send_updates, every: 1
@@ -64,11 +67,22 @@ class ActionCable::Channel::PeriodicTimersTest < ActiveSupport::TestCase
end
test "timer start and stop" do
- @connection.server.event_loop.expects(:timer).times(3).returns(stub(shutdown: nil))
- channel = ChatChannel.new @connection, "{id: 1}", id: 1
+ mock = Minitest::Mock.new
+ 3.times { mock.expect(:shutdown, nil) }
+
+ assert_called(
+ @connection.server.event_loop,
+ :timer,
+ times: 3,
+ returns: mock
+ ) do
+ channel = ChatChannel.new @connection, "{id: 1}", id: 1
+
+ channel.subscribe_to_channel
+ channel.unsubscribe_from_channel
+ assert_equal [], channel.send(:active_periodic_timers)
+ end
- channel.subscribe_to_channel
- channel.unsubscribe_from_channel
- assert_equal [], channel.send(:active_periodic_timers)
+ assert mock.verify
end
end
diff --git a/actioncable/test/channel/rejection_test.rb b/actioncable/test/channel/rejection_test.rb
index a6da014a21..897efeb65a 100644
--- a/actioncable/test/channel/rejection_test.rb
+++ b/actioncable/test/channel/rejection_test.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
require "test_helper"
+require "minitest/mock"
require "stubs/test_connection"
require "stubs/room"
@@ -20,24 +21,36 @@ class ActionCable::Channel::RejectionTest < ActiveSupport::TestCase
end
test "subscription rejection" do
- @connection.expects(:subscriptions).returns mock().tap { |m| m.expects(:remove_subscription).with instance_of(SecretChannel) }
- @channel = SecretChannel.new @connection, "{id: 1}", id: 1
- @channel.subscribe_to_channel
+ subscriptions = Minitest::Mock.new
+ subscriptions.expect(:remove_subscription, SecretChannel, [SecretChannel])
- expected = { "identifier" => "{id: 1}", "type" => "reject_subscription" }
- assert_equal expected, @connection.last_transmission
+ @connection.stub(:subscriptions, subscriptions) do
+ @channel = SecretChannel.new @connection, "{id: 1}", id: 1
+ @channel.subscribe_to_channel
+
+ expected = { "identifier" => "{id: 1}", "type" => "reject_subscription" }
+ assert_equal expected, @connection.last_transmission
+ end
+
+ assert subscriptions.verify
end
test "does not execute action if subscription is rejected" do
- @connection.expects(:subscriptions).returns mock().tap { |m| m.expects(:remove_subscription).with instance_of(SecretChannel) }
- @channel = SecretChannel.new @connection, "{id: 1}", id: 1
- @channel.subscribe_to_channel
+ subscriptions = Minitest::Mock.new
+ subscriptions.expect(:remove_subscription, SecretChannel, [SecretChannel])
- expected = { "identifier" => "{id: 1}", "type" => "reject_subscription" }
- assert_equal expected, @connection.last_transmission
- assert_equal 1, @connection.transmissions.size
+ @connection.stub(:subscriptions, subscriptions) do
+ @channel = SecretChannel.new @connection, "{id: 1}", id: 1
+ @channel.subscribe_to_channel
+
+ expected = { "identifier" => "{id: 1}", "type" => "reject_subscription" }
+ assert_equal expected, @connection.last_transmission
+ assert_equal 1, @connection.transmissions.size
+
+ @channel.perform_action("action" => :secret_action)
+ assert_equal 1, @connection.transmissions.size
+ end
- @channel.perform_action("action" => :secret_action)
- assert_equal 1, @connection.transmissions.size
+ assert subscriptions.verify
end
end
diff --git a/actioncable/test/channel/stream_test.rb b/actioncable/test/channel/stream_test.rb
index b4b118846d..ed42f1acd4 100644
--- a/actioncable/test/channel/stream_test.rb
+++ b/actioncable/test/channel/stream_test.rb
@@ -2,6 +2,7 @@
require "test_helper"
require "active_support/testing/method_call_assertions"
+require "minitest/mock"
require "stubs/test_connection"
require "stubs/room"
@@ -54,40 +55,58 @@ module ActionCable::StreamTests
test "streaming start and stop" do
run_in_eventmachine do
connection = TestConnection.new
- connection.pubsub.expects(:subscribe).with("test_room_1", kind_of(Proc), kind_of(Proc))
- channel = ChatChannel.new connection, "{id: 1}", id: 1
- channel.subscribe_to_channel
+ pubsub = Minitest::Mock.new connection.pubsub
- wait_for_async
+ pubsub.expect(:subscribe, nil, ["test_room_1", Proc, Proc])
+ pubsub.expect(:unsubscribe, nil, ["test_room_1", Proc])
+
+ connection.stub(:pubsub, pubsub) do
+ channel = ChatChannel.new connection, "{id: 1}", id: 1
+ channel.subscribe_to_channel
- connection.pubsub.expects(:unsubscribe)
- channel.unsubscribe_from_channel
+ wait_for_async
+ channel.unsubscribe_from_channel
+ end
+
+ assert pubsub.verify
end
end
test "stream from non-string channel" do
run_in_eventmachine do
connection = TestConnection.new
- connection.pubsub.expects(:subscribe).with("channel", kind_of(Proc), kind_of(Proc))
+ pubsub = Minitest::Mock.new connection.pubsub
- channel = SymbolChannel.new connection, ""
- channel.subscribe_to_channel
+ pubsub.expect(:subscribe, nil, ["channel", Proc, Proc])
+ pubsub.expect(:unsubscribe, nil, ["channel", Proc])
- wait_for_async
+ connection.stub(:pubsub, pubsub) do
+ channel = SymbolChannel.new connection, ""
+ channel.subscribe_to_channel
+
+ wait_for_async
+
+ channel.unsubscribe_from_channel
+ end
- connection.pubsub.expects(:unsubscribe)
- channel.unsubscribe_from_channel
+ assert pubsub.verify
end
end
test "stream_for" do
run_in_eventmachine do
connection = TestConnection.new
- connection.pubsub.expects(:subscribe).with("action_cable:stream_tests:chat:Room#1-Campfire", kind_of(Proc), kind_of(Proc))
channel = ChatChannel.new connection, ""
channel.subscribe_to_channel
channel.stream_for Room.new(1)
+ wait_for_async
+
+ pubsub_call = channel.pubsub.class.class_variable_get "@@subscribe_called"
+
+ assert_equal "action_cable:stream_tests:chat:Room#1-Campfire", pubsub_call[:channel]
+ assert_instance_of Proc, pubsub_call[:callback]
+ assert_instance_of Proc, pubsub_call[:success_callback]
end
end
diff --git a/actioncable/test/connection/client_socket_test.rb b/actioncable/test/connection/client_socket_test.rb
index da72501c8e..07bdc7c52a 100644
--- a/actioncable/test/connection/client_socket_test.rb
+++ b/actioncable/test/connection/client_socket_test.rb
@@ -43,10 +43,11 @@ class ActionCable::Connection::ClientSocketTest < ActionCable::TestCase
# Internal hax = :(
client = connection.websocket.send(:websocket)
- client.instance_variable_get("@stream").expects(:write).raises("foo")
+ client.instance_variable_get("@stream").stub(:write, proc { raise "foo" }) do
- assert_not_called(client, :client_gone) do
- client.write("boo")
+ assert_not_called(client, :client_gone) do
+ client.write("boo")
+ end
end
assert_equal %w[ foo ], connection.errors
end
diff --git a/actioncable/test/connection/identifier_test.rb b/actioncable/test/connection/identifier_test.rb
index 204197c2a7..a7e23b4cd8 100644
--- a/actioncable/test/connection/identifier_test.rb
+++ b/actioncable/test/connection/identifier_test.rb
@@ -30,13 +30,16 @@ class ActionCable::Connection::IdentifierTest < ActionCable::TestCase
run_in_eventmachine do
server = TestServer.new
- server.pubsub.expects(:subscribe)
- .with("action_cable/User#lifo", kind_of(Proc))
- server.pubsub.expects(:unsubscribe)
- .with("action_cable/User#lifo", kind_of(Proc))
-
open_connection(server)
close_connection
+ wait_for_async
+
+ %w[subscribe unsubscribe].each do |method|
+ pubsub_call = server.pubsub.class.class_variable_get "@@#{method}_called"
+
+ assert_equal "action_cable/User#lifo", pubsub_call[:channel]
+ assert_instance_of Proc, pubsub_call[:callback]
+ end
end
end
diff --git a/actioncable/test/connection/stream_test.rb b/actioncable/test/connection/stream_test.rb
index 1e1466af31..daf7c37c79 100644
--- a/actioncable/test/connection/stream_test.rb
+++ b/actioncable/test/connection/stream_test.rb
@@ -2,6 +2,7 @@
require "test_helper"
require "active_support/testing/method_call_assertions"
+require "minitest/mock"
require "stubs/test_server"
class ActionCable::Connection::StreamTest < ActionCable::TestCase
@@ -44,10 +45,11 @@ class ActionCable::Connection::StreamTest < ActionCable::TestCase
# Internal hax = :(
client = connection.websocket.send(:websocket)
- client.instance_variable_get("@stream").instance_variable_get("@rack_hijack_io").expects(:write).raises(closed_exception, "foo")
-
- assert_called(client, :client_gone) do
- client.write("boo")
+ rack_hijack_io = client.instance_variable_get("@stream").instance_variable_get("@rack_hijack_io")
+ rack_hijack_io.stub(:write, proc { raise(closed_exception, "foo") }) do
+ assert_called(client, :client_gone) do
+ client.write("boo")
+ end
end
assert_equal [], connection.errors
end
diff --git a/actioncable/test/stubs/test_adapter.rb b/actioncable/test/stubs/test_adapter.rb
index c481046973..5f23a137ea 100644
--- a/actioncable/test/stubs/test_adapter.rb
+++ b/actioncable/test/stubs/test_adapter.rb
@@ -1,12 +1,16 @@
# frozen_string_literal: true
class SuccessAdapter < ActionCable::SubscriptionAdapter::Base
+ class << self; attr_accessor :subscribe_called, :unsubscribe_called end
+
def broadcast(channel, payload)
end
def subscribe(channel, callback, success_callback = nil)
+ @@subscribe_called = { channel: channel, callback: callback, success_callback: success_callback }
end
def unsubscribe(channel, callback)
+ @@unsubscribe_called = { channel: channel, callback: callback }
end
end
diff --git a/actioncable/test/stubs/test_connection.rb b/actioncable/test/stubs/test_connection.rb
index fdddd1159e..155c68e38c 100644
--- a/actioncable/test/stubs/test_connection.rb
+++ b/actioncable/test/stubs/test_connection.rb
@@ -3,7 +3,7 @@
require "stubs/user"
class TestConnection
- attr_reader :identifiers, :logger, :current_user, :server, :transmissions
+ attr_reader :identifiers, :logger, :current_user, :server, :subscriptions, :transmissions
delegate :pubsub, to: :server
diff --git a/actioncable/test/test_helper.rb b/actioncable/test/test_helper.rb
index 2f186b7193..755f7b71b4 100644
--- a/actioncable/test/test_helper.rb
+++ b/actioncable/test/test_helper.rb
@@ -4,7 +4,6 @@ require "action_cable"
require "active_support/testing/autorun"
require "puma"
-require "mocha/minitest"
require "rack/mock"
begin
diff --git a/actionmailer/CHANGELOG.md b/actionmailer/CHANGELOG.md
index 6d91d4fbd6..88e8a36eaa 100644
--- a/actionmailer/CHANGELOG.md
+++ b/actionmailer/CHANGELOG.md
@@ -6,6 +6,14 @@
*Gannon McGibbon*
+* Add `Base.unregister_observer`, `Base.unregister_observers`,
+ `Base.unregister_interceptor`, `Base.unregister_interceptors`,
+ `Base.unregister_preview_interceptor` and `Base.unregister_preview_interceptors`.
+ This makes it possible to dynamically add and remove email observers and
+ interceptors at runtime in the same way they're registered.
+
+ *Claudio Ortolina*, *Kota Miyake*
+
* Rails 6 requires Ruby 2.4.1 or newer.
*Jeremy Daer*
diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb
index 3af95081ee..7f22af83b0 100644
--- a/actionmailer/lib/action_mailer/base.rb
+++ b/actionmailer/lib/action_mailer/base.rb
@@ -475,11 +475,21 @@ module ActionMailer
observers.flatten.compact.each { |observer| register_observer(observer) }
end
+ # Unregister one or more previously registered Observers.
+ def unregister_observers(*observers)
+ observers.flatten.compact.each { |observer| unregister_observer(observer) }
+ end
+
# Register one or more Interceptors which will be called before mail is sent.
def register_interceptors(*interceptors)
interceptors.flatten.compact.each { |interceptor| register_interceptor(interceptor) }
end
+ # Unregister one or more previously registered Interceptors.
+ def unregister_interceptors(*interceptors)
+ interceptors.flatten.compact.each { |interceptor| unregister_interceptor(interceptor) }
+ end
+
# Register an Observer which will be notified when mail is delivered.
# Either a class, string or symbol can be passed in as the Observer.
# If a string or symbol is passed in it will be camelized and constantized.
@@ -487,6 +497,13 @@ module ActionMailer
Mail.register_observer(observer_class_for(observer))
end
+ # Unregister a previously registered Observer.
+ # Either a class, string or symbol can be passed in as the Observer.
+ # If a string or symbol is passed in it will be camelized and constantized.
+ def unregister_observer(observer)
+ Mail.unregister_observer(observer_class_for(observer))
+ end
+
# Register an Interceptor which will be called before mail is sent.
# Either a class, string or symbol can be passed in as the Interceptor.
# If a string or symbol is passed in it will be camelized and constantized.
@@ -494,6 +511,13 @@ module ActionMailer
Mail.register_interceptor(observer_class_for(interceptor))
end
+ # Unregister a previously registered Interceptor.
+ # Either a class, string or symbol can be passed in as the Interceptor.
+ # If a string or symbol is passed in it will be camelized and constantized.
+ def unregister_interceptor(interceptor)
+ Mail.unregister_interceptor(observer_class_for(interceptor))
+ end
+
def observer_class_for(value) # :nodoc:
case value
when String, Symbol
diff --git a/actionmailer/lib/action_mailer/preview.rb b/actionmailer/lib/action_mailer/preview.rb
index 0aea84fd2b..500b3bede0 100644
--- a/actionmailer/lib/action_mailer/preview.rb
+++ b/actionmailer/lib/action_mailer/preview.rb
@@ -31,22 +31,39 @@ module ActionMailer
interceptors.flatten.compact.each { |interceptor| register_preview_interceptor(interceptor) }
end
+ # Unregister one or more previously registered Interceptors.
+ def unregister_preview_interceptors(*interceptors)
+ interceptors.flatten.compact.each { |interceptor| unregister_preview_interceptor(interceptor) }
+ end
+
# Register an Interceptor which will be called before mail is previewed.
# Either a class or a string can be passed in as the Interceptor. If a
# string is passed in it will be constantized.
def register_preview_interceptor(interceptor)
- preview_interceptor = \
+ preview_interceptor = interceptor_class_for(interceptor)
+
+ unless preview_interceptors.include?(preview_interceptor)
+ preview_interceptors << preview_interceptor
+ end
+ end
+
+ # Unregister a previously registered Interceptor.
+ # Either a class or a string can be passed in as the Interceptor. If a
+ # string is passed in it will be constantized.
+ def unregister_preview_interceptor(interceptor)
+ preview_interceptors.delete(interceptor_class_for(interceptor))
+ end
+
+ private
+
+ def interceptor_class_for(interceptor)
case interceptor
when String, Symbol
interceptor.to_s.camelize.constantize
else
interceptor
end
-
- unless preview_interceptors.include?(preview_interceptor)
- preview_interceptors << preview_interceptor
end
- end
end
end
diff --git a/actionmailer/test/base_test.rb b/actionmailer/test/base_test.rb
index 4124aa00bd..7898996c30 100644
--- a/actionmailer/test/base_test.rb
+++ b/actionmailer/test/base_test.rb
@@ -618,37 +618,52 @@ class BaseTest < ActiveSupport::TestCase
end
end
- test "you can register an observer to the mail object that gets informed on email delivery" do
+ test "you can register and unregister an observer to the mail object that gets informed on email delivery" do
mail_side_effects do
ActionMailer::Base.register_observer(MyObserver)
mail = BaseMailer.welcome
assert_called_with(MyObserver, :delivered_email, [mail]) do
mail.deliver_now
end
+
+ ActionMailer::Base.unregister_observer(MyObserver)
+ assert_not_called(MyObserver, :delivered_email, returns: mail) do
+ mail.deliver_now
+ end
end
end
- test "you can register an observer using its stringified name to the mail object that gets informed on email delivery" do
+ test "you can register and unregister an observer using its stringified name to the mail object that gets informed on email delivery" do
mail_side_effects do
ActionMailer::Base.register_observer("BaseTest::MyObserver")
mail = BaseMailer.welcome
assert_called_with(MyObserver, :delivered_email, [mail]) do
mail.deliver_now
end
+
+ ActionMailer::Base.unregister_observer("BaseTest::MyObserver")
+ assert_not_called(MyObserver, :delivered_email, returns: mail) do
+ mail.deliver_now
+ end
end
end
- test "you can register an observer using its symbolized underscored name to the mail object that gets informed on email delivery" do
+ test "you can register and unregister an observer using its symbolized underscored name to the mail object that gets informed on email delivery" do
mail_side_effects do
ActionMailer::Base.register_observer(:"base_test/my_observer")
mail = BaseMailer.welcome
assert_called_with(MyObserver, :delivered_email, [mail]) do
mail.deliver_now
end
+
+ ActionMailer::Base.unregister_observer(:"base_test/my_observer")
+ assert_not_called(MyObserver, :delivered_email, returns: mail) do
+ mail.deliver_now
+ end
end
end
- test "you can register multiple observers to the mail object that both get informed on email delivery" do
+ test "you can register and unregister multiple observers to the mail object that both get informed on email delivery" do
mail_side_effects do
ActionMailer::Base.register_observers("BaseTest::MyObserver", MySecondObserver)
mail = BaseMailer.welcome
@@ -657,6 +672,14 @@ class BaseTest < ActiveSupport::TestCase
mail.deliver_now
end
end
+
+ ActionMailer::Base.unregister_observers("BaseTest::MyObserver", MySecondObserver)
+ assert_not_called(MyObserver, :delivered_email, returns: mail) do
+ mail.deliver_now
+ end
+ assert_not_called(MySecondObserver, :delivered_email, returns: mail) do
+ mail.deliver_now
+ end
end
end
@@ -670,37 +693,52 @@ class BaseTest < ActiveSupport::TestCase
def self.previewing_email(mail); end
end
- test "you can register an interceptor to the mail object that gets passed the mail object before delivery" do
+ test "you can register and unregister an interceptor to the mail object that gets passed the mail object before delivery" do
mail_side_effects do
ActionMailer::Base.register_interceptor(MyInterceptor)
mail = BaseMailer.welcome
assert_called_with(MyInterceptor, :delivering_email, [mail]) do
mail.deliver_now
end
+
+ ActionMailer::Base.unregister_interceptor(MyInterceptor)
+ assert_not_called(MyInterceptor, :delivering_email, returns: mail) do
+ mail.deliver_now
+ end
end
end
- test "you can register an interceptor using its stringified name to the mail object that gets passed the mail object before delivery" do
+ test "you can register and unregister an interceptor using its stringified name to the mail object that gets passed the mail object before delivery" do
mail_side_effects do
ActionMailer::Base.register_interceptor("BaseTest::MyInterceptor")
mail = BaseMailer.welcome
assert_called_with(MyInterceptor, :delivering_email, [mail]) do
mail.deliver_now
end
+
+ ActionMailer::Base.unregister_interceptor("BaseTest::MyInterceptor")
+ assert_not_called(MyInterceptor, :delivering_email, returns: mail) do
+ mail.deliver_now
+ end
end
end
- test "you can register an interceptor using its symbolized underscored name to the mail object that gets passed the mail object before delivery" do
+ test "you can register and unregister an interceptor using its symbolized underscored name to the mail object that gets passed the mail object before delivery" do
mail_side_effects do
ActionMailer::Base.register_interceptor(:"base_test/my_interceptor")
mail = BaseMailer.welcome
assert_called_with(MyInterceptor, :delivering_email, [mail]) do
mail.deliver_now
end
+
+ ActionMailer::Base.unregister_interceptor(:"base_test/my_interceptor")
+ assert_not_called(MyInterceptor, :delivering_email, returns: mail) do
+ mail.deliver_now
+ end
end
end
- test "you can register multiple interceptors to the mail object that both get passed the mail object before delivery" do
+ test "you can register and unregister multiple interceptors to the mail object that both get passed the mail object before delivery" do
mail_side_effects do
ActionMailer::Base.register_interceptors("BaseTest::MyInterceptor", MySecondInterceptor)
mail = BaseMailer.welcome
@@ -709,6 +747,14 @@ class BaseTest < ActiveSupport::TestCase
mail.deliver_now
end
end
+
+ ActionMailer::Base.unregister_interceptors("BaseTest::MyInterceptor", MySecondInterceptor)
+ assert_not_called(MyInterceptor, :delivering_email, returns: mail) do
+ mail.deliver_now
+ end
+ assert_not_called(MySecondInterceptor, :delivering_email, returns: mail) do
+ mail.deliver_now
+ end
end
end
@@ -888,8 +934,6 @@ class BaseTest < ActiveSupport::TestCase
klass.default_params = old
end
- # A simple hack to restore the observers and interceptors for Mail, as it
- # does not have an unregister API yet.
def mail_side_effects
old_observers = Mail.class_variable_get(:@@delivery_notification_observers)
old_delivery_interceptors = Mail.class_variable_get(:@@delivery_interceptors)
@@ -928,7 +972,7 @@ class BasePreviewInterceptorsTest < ActiveSupport::TestCase
def self.previewing_email(mail); end
end
- test "you can register a preview interceptor to the mail object that gets passed the mail object before previewing" do
+ test "you can register and unregister a preview interceptor to the mail object that gets passed the mail object before previewing" do
ActionMailer::Base.register_preview_interceptor(MyInterceptor)
mail = BaseMailer.welcome
stub_any_instance(BaseMailerPreview) do |instance|
@@ -938,9 +982,14 @@ class BasePreviewInterceptorsTest < ActiveSupport::TestCase
end
end
end
+
+ ActionMailer::Base.unregister_preview_interceptor(MyInterceptor)
+ assert_not_called(MyInterceptor, :previewing_email, returns: mail) do
+ BaseMailerPreview.call(:welcome)
+ end
end
- test "you can register a preview interceptor using its stringified name to the mail object that gets passed the mail object before previewing" do
+ test "you can register and unregister a preview interceptor using its stringified name to the mail object that gets passed the mail object before previewing" do
ActionMailer::Base.register_preview_interceptor("BasePreviewInterceptorsTest::MyInterceptor")
mail = BaseMailer.welcome
stub_any_instance(BaseMailerPreview) do |instance|
@@ -950,9 +999,14 @@ class BasePreviewInterceptorsTest < ActiveSupport::TestCase
end
end
end
+
+ ActionMailer::Base.unregister_preview_interceptor("BasePreviewInterceptorsTest::MyInterceptor")
+ assert_not_called(MyInterceptor, :previewing_email, returns: mail) do
+ BaseMailerPreview.call(:welcome)
+ end
end
- test "you can register an interceptor using its symbolized underscored name to the mail object that gets passed the mail object before previewing" do
+ test "you can register and unregister a preview interceptor using its symbolized underscored name to the mail object that gets passed the mail object before previewing" do
ActionMailer::Base.register_preview_interceptor(:"base_preview_interceptors_test/my_interceptor")
mail = BaseMailer.welcome
stub_any_instance(BaseMailerPreview) do |instance|
@@ -962,9 +1016,14 @@ class BasePreviewInterceptorsTest < ActiveSupport::TestCase
end
end
end
+
+ ActionMailer::Base.unregister_preview_interceptor(:"base_preview_interceptors_test/my_interceptor")
+ assert_not_called(MyInterceptor, :previewing_email, returns: mail) do
+ BaseMailerPreview.call(:welcome)
+ end
end
- test "you can register multiple preview interceptors to the mail object that both get passed the mail object before previewing" do
+ test "you can register and unregister multiple preview interceptors to the mail object that both get passed the mail object before previewing" do
ActionMailer::Base.register_preview_interceptors("BasePreviewInterceptorsTest::MyInterceptor", MySecondInterceptor)
mail = BaseMailer.welcome
stub_any_instance(BaseMailerPreview) do |instance|
@@ -976,6 +1035,14 @@ class BasePreviewInterceptorsTest < ActiveSupport::TestCase
end
end
end
+
+ ActionMailer::Base.unregister_preview_interceptors("BasePreviewInterceptorsTest::MyInterceptor", MySecondInterceptor)
+ assert_not_called(MyInterceptor, :previewing_email, returns: mail) do
+ BaseMailerPreview.call(:welcome)
+ end
+ assert_not_called(MySecondInterceptor, :previewing_email, returns: mail) do
+ BaseMailerPreview.call(:welcome)
+ end
end
end
diff --git a/actionpack/lib/action_controller/metal/request_forgery_protection.rb b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
index 953f3c47ed..4bae795438 100644
--- a/actionpack/lib/action_controller/metal/request_forgery_protection.rb
+++ b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
@@ -275,7 +275,7 @@ module ActionController #:nodoc:
# Check for cross-origin JavaScript responses.
def non_xhr_javascript_response? # :doc:
- content_type =~ %r(\Atext/javascript) && !request.xhr?
+ content_type =~ %r(\A(?:text|application)/javascript) && !request.xhr?
end
AUTHENTICITY_TOKEN_LENGTH = 32
diff --git a/actionpack/test/controller/request_forgery_protection_test.rb b/actionpack/test/controller/request_forgery_protection_test.rb
index 7a02c27c99..ea94a3e048 100644
--- a/actionpack/test/controller/request_forgery_protection_test.rb
+++ b/actionpack/test/controller/request_forgery_protection_test.rb
@@ -521,6 +521,11 @@ module RequestForgeryProtectionTests
get :negotiate_same_origin
end
+ assert_cross_origin_blocked do
+ @request.accept = "application/javascript"
+ get :negotiate_same_origin
+ end
+
assert_cross_origin_not_blocked { get :same_origin_js, xhr: true }
assert_cross_origin_not_blocked { get :same_origin_js, xhr: true, format: "js" }
assert_cross_origin_not_blocked do
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index 5cefb5dfd7..d101b81e28 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,7 @@
+* Bump minimum SQLite version to 3.8
+
+ *Yasuo Honda*
+
* Fix parent record should not get saved with duplicate children records.
Fixes #32940.
diff --git a/activestorage/app/models/active_storage/blob.rb b/activestorage/app/models/active_storage/blob.rb
index d36c951292..203e4118c5 100644
--- a/activestorage/app/models/active_storage/blob.rb
+++ b/activestorage/app/models/active_storage/blob.rb
@@ -168,6 +168,16 @@ class ActiveStorage::Blob < ActiveRecord::Base
# Downloads the blob to a tempfile on disk. Yields the tempfile.
#
+ # The tempfile's name is prefixed with +ActiveStorage-+ and the blob's ID. Its extension matches that of the blob.
+ #
+ # By default, the tempfile is created in <tt>Dir.tmpdir</tt>. Pass +tempdir:+ to create it in a different directory:
+ #
+ # blob.open(tempdir: "/path/to/tmp") do |file|
+ # # ...
+ # end
+ #
+ # The tempfile is automatically closed and unlinked after the given block is executed.
+ #
# Raises ActiveStorage::IntegrityError if the downloaded data does not match the blob's checksum.
def open(tempdir: nil, &block)
ActiveStorage::Downloader.new(self, tempdir: tempdir).download_blob_to_tempfile(&block)
diff --git a/activestorage/lib/active_storage/downloader.rb b/activestorage/lib/active_storage/downloader.rb
index 2aa56a729a..87be6efb05 100644
--- a/activestorage/lib/active_storage/downloader.rb
+++ b/activestorage/lib/active_storage/downloader.rb
@@ -19,7 +19,7 @@ module ActiveStorage
attr_reader :blob, :tempdir
def open_tempfile
- file = Tempfile.open([ "ActiveStorage", tempfile_extension_with_delimiter ], tempdir)
+ file = Tempfile.open([ "ActiveStorage-#{blob.id}-", blob.filename.extension_with_delimiter ], tempdir)
begin
yield file
@@ -40,9 +40,5 @@ module ActiveStorage
raise ActiveStorage::IntegrityError
end
end
-
- def tempfile_extension_with_delimiter
- blob.filename.extension_with_delimiter
- end
end
end
diff --git a/activestorage/test/models/blob_test.rb b/activestorage/test/models/blob_test.rb
index 2d1857041d..88ce0f868a 100644
--- a/activestorage/test/models/blob_test.rb
+++ b/activestorage/test/models/blob_test.rb
@@ -85,11 +85,14 @@ class ActiveStorage::BlobTest < ActiveSupport::TestCase
end
test "open with integrity" do
- create_file_blob(filename: "racecar.jpg").open do |file|
- assert file.binmode?
- assert_equal 0, file.pos
- assert_match(/\.jpg\z/, file.path)
- assert_equal file_fixture("racecar.jpg").binread, file.read, "Expected downloaded file to match fixture file"
+ create_file_blob(filename: "racecar.jpg").tap do |blob|
+ blob.open do |file|
+ assert file.binmode?
+ assert_equal 0, file.pos
+ assert File.basename(file.path).starts_with?("ActiveStorage-#{blob.id}-")
+ assert file.path.ends_with?(".jpg")
+ assert_equal file_fixture("racecar.jpg").binread, file.read, "Expected downloaded file to match fixture file"
+ end
end
end
diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md
index 91818c3112..100d57aa16 100644
--- a/activesupport/CHANGELOG.md
+++ b/activesupport/CHANGELOG.md
@@ -20,7 +20,7 @@
%i( title body ).index_with(nil)
# => { title: nil, body: nil }
- Closely linked with its brethen `index_by`.
+ Closely linked with `index_by`, which creates a hash where the keys are extracted from a block.
*Kasper Timm Hansen*
diff --git a/activesupport/lib/active_support/i18n_railtie.rb b/activesupport/lib/active_support/i18n_railtie.rb
index ce8bfbfd8c..93bde57f6a 100644
--- a/activesupport/lib/active_support/i18n_railtie.rb
+++ b/activesupport/lib/active_support/i18n_railtie.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
require "active_support"
-require "active_support/file_update_checker"
require "active_support/core_ext/array/wrap"
# :enddoc:
diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb
index 5f709c5fd9..792c88415c 100644
--- a/activesupport/lib/active_support/values/time_zone.rb
+++ b/activesupport/lib/active_support/values/time_zone.rb
@@ -354,8 +354,13 @@ module ActiveSupport
# Time.zone = 'Hawaii' # => "Hawaii"
# Time.utc(2000).to_f # => 946684800.0
# Time.zone.at(946684800.0) # => Fri, 31 Dec 1999 14:00:00 HST -10:00
- def at(secs)
- Time.at(secs).utc.in_time_zone(self)
+ #
+ # A second argument can be supplied to specify sub-second precision.
+ #
+ # Time.zone = 'Hawaii' # => "Hawaii"
+ # Time.at(946684800, 123456.789).nsec # => 123456789
+ def at(*args)
+ Time.at(*args).utc.in_time_zone(self)
end
# Method for creating new ActiveSupport::TimeWithZone instance in time zone
diff --git a/activesupport/test/time_zone_test.rb b/activesupport/test/time_zone_test.rb
index b59f3e9405..6d45a6726d 100644
--- a/activesupport/test/time_zone_test.rb
+++ b/activesupport/test/time_zone_test.rb
@@ -225,6 +225,16 @@ class TimeZoneTest < ActiveSupport::TestCase
assert_equal secs, twz.to_f
end
+ def test_at_with_microseconds
+ zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"]
+ secs = 946684800.0
+ microsecs = 123456.789
+ twz = zone.at(secs, microsecs)
+ assert_equal zone, twz.time_zone
+ assert_equal secs, twz.to_i
+ assert_equal 123456789, twz.nsec
+ end
+
def test_iso8601
zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"]
twz = zone.iso8601("1999-12-31T19:00:00")