diff options
326 files changed, 6102 insertions, 2612 deletions
diff --git a/.rubocop.yml b/.rubocop.yml index 7327f1e631..3e3b963a47 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -52,6 +52,9 @@ Layout/EndAlignment: Layout/EmptyLineAfterMagicComment: Enabled: true +Layout/EmptyLinesAroundBlockBody: + Enabled: true + # In a regular class definition, no empty lines around the body. Layout/EmptyLinesAroundClassBody: Enabled: true diff --git a/.travis.yml b/.travis.yml index 0fdea1367c..d7544fecb6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -91,7 +91,7 @@ matrix: env: - "GEM=ar:mysql2 MYSQL=mariadb" addons: - mariadb: 10.2 + mariadb: 10.3 - rvm: 2.5.1 env: - "GEM=ar:sqlite3_mem" diff --git a/Gemfile.lock b/Gemfile.lock index 4a0fba9024..9c28735a0d 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) - et-orbi (1.0.8) + 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.3) + 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.6) 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,58 +449,57 @@ 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) + sprockets (3.7.2) 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) turbolinks (5.1.1) turbolinks-source (~> 5.1) turbolinks-source (5.1.0) - tzinfo (1.2.3) + 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 @@ -569,4 +575,4 @@ DEPENDENCIES websocket-client-simple! BUNDLED WITH - 1.16.1 + 1.16.2 diff --git a/actioncable/lib/action_cable/connection/stream.rb b/actioncable/lib/action_cable/connection/stream.rb index 4873026b71..e658948a55 100644 --- a/actioncable/lib/action_cable/connection/stream.rb +++ b/actioncable/lib/action_cable/connection/stream.rb @@ -98,8 +98,10 @@ module ActionCable def hijack_rack_socket return unless @socket_object.env["rack.hijack"] - @socket_object.env["rack.hijack"].call - @rack_hijack_io = @socket_object.env["rack.hijack_io"] + # This should return the underlying io according to the SPEC: + @rack_hijack_io = @socket_object.env["rack.hijack"].call + # Retain existing behaviour if required: + @rack_hijack_io ||= @socket_object.env["rack.hijack_io"] @event_loop.attach(@rack_hijack_io, self) end diff --git a/actioncable/lib/action_cable/subscription_adapter/postgresql.rb b/actioncable/lib/action_cable/subscription_adapter/postgresql.rb index e384ea4afb..50ec438c3a 100644 --- a/actioncable/lib/action_cable/subscription_adapter/postgresql.rb +++ b/actioncable/lib/action_cable/subscription_adapter/postgresql.rb @@ -14,7 +14,7 @@ module ActionCable end def broadcast(channel, payload) - with_connection do |pg_conn| + with_broadcast_connection do |pg_conn| pg_conn.exec("NOTIFY #{pg_conn.escape_identifier(channel_identifier(channel))}, '#{pg_conn.escape_string(payload)}'") end end @@ -31,14 +31,24 @@ module ActionCable listener.shutdown end - def with_connection(&block) # :nodoc: - ActiveRecord::Base.connection_pool.with_connection do |ar_conn| - pg_conn = ar_conn.raw_connection + def with_subscriptions_connection(&block) # :nodoc: + ar_conn = ActiveRecord::Base.connection_pool.checkout.tap do |conn| + # Action Cable is taking ownership over this database connection, and + # will perform the necessary cleanup tasks + ActiveRecord::Base.connection_pool.remove(conn) + end + pg_conn = ar_conn.raw_connection - unless pg_conn.is_a?(PG::Connection) - raise "The Active Record database must be PostgreSQL in order to use the PostgreSQL Action Cable storage adapter" - end + verify!(pg_conn) + yield pg_conn + ensure + ar_conn.disconnect! + end + def with_broadcast_connection(&block) # :nodoc: + ActiveRecord::Base.connection_pool.with_connection do |ar_conn| + pg_conn = ar_conn.raw_connection + verify!(pg_conn) yield pg_conn end end @@ -52,6 +62,12 @@ module ActionCable @listener || @server.mutex.synchronize { @listener ||= Listener.new(self, @server.event_loop) } end + def verify!(pg_conn) + unless pg_conn.is_a?(PG::Connection) + raise "The Active Record database must be PostgreSQL in order to use the PostgreSQL Action Cable storage adapter" + end + end + class Listener < SubscriberMap def initialize(adapter, event_loop) super() @@ -67,7 +83,7 @@ module ActionCable end def listen - @adapter.with_connection do |pg_conn| + @adapter.with_subscriptions_connection do |pg_conn| catch :shutdown do loop do until @queue.empty? diff --git a/actioncable/test/channel/base_test.rb b/actioncable/test/channel/base_test.rb index 3b8eb63975..eb0e1673b0 100644 --- a/actioncable/test/channel/base_test.rb +++ b/actioncable/test/channel/base_test.rb @@ -1,10 +1,11 @@ # frozen_string_literal: true require "test_helper" +require "minitest/mock" require "stubs/test_connection" require "stubs/room" -class ActionCable::Channel::BaseTest < ActiveSupport::TestCase +class ActionCable::Channel::BaseTest < ActionCable::TestCase class ActionCable::Channel::Base def kick @last_action = [ :kick ] @@ -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..2cbfabc1d0 100644 --- a/actioncable/test/channel/broadcasting_test.rb +++ b/actioncable/test/channel/broadcasting_test.rb @@ -4,7 +4,7 @@ require "test_helper" require "stubs/test_connection" require "stubs/room" -class ActionCable::Channel::BroadcastingTest < ActiveSupport::TestCase +class ActionCable::Channel::BroadcastingTest < ActionCable::TestCase class ChatChannel < ActionCable::Channel::Base end @@ -13,8 +13,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/naming_test.rb b/actioncable/test/channel/naming_test.rb index 6f094fbb5e..45652d9cc9 100644 --- a/actioncable/test/channel/naming_test.rb +++ b/actioncable/test/channel/naming_test.rb @@ -2,7 +2,7 @@ require "test_helper" -class ActionCable::Channel::NamingTest < ActiveSupport::TestCase +class ActionCable::Channel::NamingTest < ActionCable::TestCase class ChatChannel < ActionCable::Channel::Base end diff --git a/actioncable/test/channel/periodic_timers_test.rb b/actioncable/test/channel/periodic_timers_test.rb index 500b984ca6..0c979f4c7c 100644 --- a/actioncable/test/channel/periodic_timers_test.rb +++ b/actioncable/test/channel/periodic_timers_test.rb @@ -5,7 +5,7 @@ require "stubs/test_connection" require "stubs/room" require "active_support/time" -class ActionCable::Channel::PeriodicTimersTest < ActiveSupport::TestCase +class ActionCable::Channel::PeriodicTimersTest < ActionCable::TestCase class ChatChannel < ActionCable::Channel::Base # Method name arg periodically :send_updates, every: 1 @@ -64,11 +64,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) } - channel.subscribe_to_channel - channel.unsubscribe_from_channel - assert_equal [], channel.send(:active_periodic_timers) + 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 + + assert mock.verify end end diff --git a/actioncable/test/channel/rejection_test.rb b/actioncable/test/channel/rejection_test.rb index a6da014a21..683eafcac0 100644 --- a/actioncable/test/channel/rejection_test.rb +++ b/actioncable/test/channel/rejection_test.rb @@ -1,10 +1,11 @@ # frozen_string_literal: true require "test_helper" +require "minitest/mock" require "stubs/test_connection" require "stubs/room" -class ActionCable::Channel::RejectionTest < ActiveSupport::TestCase +class ActionCable::Channel::RejectionTest < ActionCable::TestCase class SecretChannel < ActionCable::Channel::Base def subscribed reject if params[:id] > 0 @@ -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 5c1f308f53..bfe1f92946 100644 --- a/actioncable/test/channel/stream_test.rb +++ b/actioncable/test/channel/stream_test.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "test_helper" -require "active_support/testing/method_call_assertions" +require "minitest/mock" require "stubs/test_connection" require "stubs/room" @@ -54,40 +54,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.pubsub.expects(:unsubscribe) - channel.unsubscribe_from_channel + connection.stub(:pubsub, pubsub) do + channel = ChatChannel.new connection, "{id: 1}", id: 1 + channel.subscribe_to_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 - connection.pubsub.expects(:unsubscribe) - channel.unsubscribe_from_channel + wait_for_async + + channel.unsubscribe_from_channel + end + + 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 @@ -145,8 +163,6 @@ module ActionCable::StreamTests end class StreamFromTest < ActionCable::TestCase - include ActiveSupport::Testing::MethodCallAssertions - setup do @server = TestServer.new(subscription_adapter: ActionCable::SubscriptionAdapter::Async) @server.config.allowed_request_origins = %w( http://rubyonrails.com ) @@ -180,7 +196,7 @@ module ActionCable::StreamTests run_in_eventmachine do connection = open_connection expected = { "identifier" => { "channel" => MultiChatChannel.name }.to_json, "type" => "confirm_subscription" } - assert_called(connection.websocket, :transmit, [expected.to_json]) do + assert_called_with(connection.websocket, :transmit, [expected.to_json]) do receive(connection, command: "subscribe", channel: MultiChatChannel.name, identifiers: {}) wait_for_async end diff --git a/actioncable/test/client_test.rb b/actioncable/test/client_test.rb index 92fe59c803..e5f43488c4 100644 --- a/actioncable/test/client_test.rb +++ b/actioncable/test/client_test.rb @@ -7,7 +7,6 @@ require "websocket-client-simple" require "json" require "active_support/hash_with_indifferent_access" -require "active_support/testing/method_call_assertions" #### # 😷 Warning suppression 😷 @@ -28,8 +27,6 @@ WebSocket::Frame::Data.prepend Module.new { #### class ClientTest < ActionCable::TestCase - include ActiveSupport::Testing::MethodCallAssertions - WAIT_WHEN_EXPECTING_EVENT = 2 WAIT_WHEN_NOT_EXPECTING_EVENT = 0.5 diff --git a/actioncable/test/connection/authorization_test.rb b/actioncable/test/connection/authorization_test.rb index be41d510ff..f77e543435 100644 --- a/actioncable/test/connection/authorization_test.rb +++ b/actioncable/test/connection/authorization_test.rb @@ -1,12 +1,9 @@ # frozen_string_literal: true require "test_helper" -require "active_support/testing/method_call_assertions" require "stubs/test_server" class ActionCable::Connection::AuthorizationTest < ActionCable::TestCase - include ActiveSupport::Testing::MethodCallAssertions - class Connection < ActionCable::Connection::Base attr_reader :websocket diff --git a/actioncable/test/connection/base_test.rb b/actioncable/test/connection/base_test.rb index 9e480ab60d..6ffa0961bc 100644 --- a/actioncable/test/connection/base_test.rb +++ b/actioncable/test/connection/base_test.rb @@ -3,11 +3,8 @@ require "test_helper" require "stubs/test_server" require "active_support/core_ext/object/json" -require "active_support/testing/method_call_assertions" class ActionCable::Connection::BaseTest < ActionCable::TestCase - include ActiveSupport::Testing::MethodCallAssertions - class Connection < ActionCable::Connection::Base attr_reader :websocket, :subscriptions, :message_buffer, :connected diff --git a/actioncable/test/connection/client_socket_test.rb b/actioncable/test/connection/client_socket_test.rb index da72501c8e..a7db32c3e4 100644 --- a/actioncable/test/connection/client_socket_test.rb +++ b/actioncable/test/connection/client_socket_test.rb @@ -2,11 +2,8 @@ require "test_helper" require "stubs/test_server" -require "active_support/testing/method_call_assertions" class ActionCable::Connection::ClientSocketTest < ActionCable::TestCase - include ActiveSupport::Testing::MethodCallAssertions - class Connection < ActionCable::Connection::Base attr_reader :connected, :websocket, :errors @@ -43,10 +40,10 @@ class ActionCable::Connection::ClientSocketTest < ActionCable::TestCase # Internal hax = :( client = connection.websocket.send(:websocket) - client.instance_variable_get("@stream").expects(:write).raises("foo") - - assert_not_called(client, :client_gone) do - client.write("boo") + client.instance_variable_get("@stream").stub(:write, proc { raise "foo" }) do + 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..707f4bab72 100644 --- a/actioncable/test/connection/identifier_test.rb +++ b/actioncable/test/connection/identifier_test.rb @@ -1,13 +1,10 @@ # frozen_string_literal: true require "test_helper" -require "active_support/testing/method_call_assertions" require "stubs/test_server" require "stubs/user" class ActionCable::Connection::IdentifierTest < ActionCable::TestCase - include ActiveSupport::Testing::MethodCallAssertions - class Connection < ActionCable::Connection::Base identified_by :current_user attr_reader :websocket @@ -30,13 +27,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..0f4576db40 100644 --- a/actioncable/test/connection/stream_test.rb +++ b/actioncable/test/connection/stream_test.rb @@ -1,12 +1,10 @@ # frozen_string_literal: true require "test_helper" -require "active_support/testing/method_call_assertions" +require "minitest/mock" require "stubs/test_server" class ActionCable::Connection::StreamTest < ActionCable::TestCase - include ActiveSupport::Testing::MethodCallAssertions - class Connection < ActionCable::Connection::Base attr_reader :connected, :websocket, :errors @@ -44,10 +42,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/connection/subscriptions_test.rb b/actioncable/test/connection/subscriptions_test.rb index 7bc8c4241c..902085c5d6 100644 --- a/actioncable/test/connection/subscriptions_test.rb +++ b/actioncable/test/connection/subscriptions_test.rb @@ -1,11 +1,8 @@ # frozen_string_literal: true require "test_helper" -require "active_support/testing/method_call_assertions" class ActionCable::Connection::SubscriptionsTest < ActionCable::TestCase - include ActiveSupport::Testing::MethodCallAssertions - class Connection < ActionCable::Connection::Base attr_reader :websocket diff --git a/actioncable/test/server/base_test.rb b/actioncable/test/server/base_test.rb index 3b5931f0a4..d46debea45 100644 --- a/actioncable/test/server/base_test.rb +++ b/actioncable/test/server/base_test.rb @@ -3,11 +3,8 @@ require "test_helper" require "stubs/test_server" require "active_support/core_ext/hash/indifferent_access" -require "active_support/testing/method_call_assertions" - -class BaseTest < ActiveSupport::TestCase - include ActiveSupport::Testing::MethodCallAssertions +class BaseTest < ActionCable::TestCase def setup @server = ActionCable::Server::Base.new @server.config.cable = { adapter: "async" }.with_indifferent_access diff --git a/actioncable/test/server/broadcasting_test.rb b/actioncable/test/server/broadcasting_test.rb index 72cec26234..03c900182a 100644 --- a/actioncable/test/server/broadcasting_test.rb +++ b/actioncable/test/server/broadcasting_test.rb @@ -3,7 +3,7 @@ require "test_helper" require "stubs/test_server" -class BroadcastingTest < ActiveSupport::TestCase +class BroadcastingTest < ActionCable::TestCase test "fetching a broadcaster converts the broadcasting queue to a string" do broadcasting = :test_queue server = TestServer.new diff --git a/actioncable/test/stubs/test_adapter.rb b/actioncable/test/stubs/test_adapter.rb index c481046973..3b25c9168f 100644 --- a/actioncable/test/stubs/test_adapter.rb +++ b/actioncable/test/stubs/test_adapter.rb @@ -5,8 +5,10 @@ class SuccessAdapter < ActionCable::SubscriptionAdapter::Base 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/subscription_adapter/postgresql_test.rb b/actioncable/test/subscription_adapter/postgresql_test.rb index 1c375188ba..5fb26a8896 100644 --- a/actioncable/test/subscription_adapter/postgresql_test.rb +++ b/actioncable/test/subscription_adapter/postgresql_test.rb @@ -39,4 +39,27 @@ class PostgresqlAdapterTest < ActionCable::TestCase def cable_config { adapter: "postgresql" } end + + def test_clear_active_record_connections_adapter_still_works + server = ActionCable::Server::Base.new + server.config.cable = cable_config.with_indifferent_access + server.config.logger = Logger.new(StringIO.new).tap { |l| l.level = Logger::UNKNOWN } + + adapter_klass = Class.new(server.config.pubsub_adapter) do + def active? + !@listener.nil? + end + end + + adapter = adapter_klass.new(server) + + subscribe_as_queue("channel", adapter) do |queue| + adapter.broadcast("channel", "hello world") + assert_equal "hello world", queue.pop + end + + ActiveRecord::Base.clear_reloadable_connections! + + assert adapter.active? + end end diff --git a/actioncable/test/subscription_adapter/redis_test.rb b/actioncable/test/subscription_adapter/redis_test.rb index 63823d6ef0..3dc995331a 100644 --- a/actioncable/test/subscription_adapter/redis_test.rb +++ b/actioncable/test/subscription_adapter/redis_test.rb @@ -4,7 +4,6 @@ require "test_helper" require_relative "common" require_relative "channel_prefix" -require "active_support/testing/method_call_assertions" require "action_cable/subscription_adapter/redis" class RedisAdapterTest < ActionCable::TestCase @@ -30,9 +29,7 @@ class RedisAdapterTest::AlternateConfiguration < RedisAdapterTest end end -class RedisAdapterTest::Connector < ActiveSupport::TestCase - include ActiveSupport::Testing::MethodCallAssertions - +class RedisAdapterTest::Connector < ActionCable::TestCase test "slices url, host, port, db, and password from config" do config = { url: 1, host: 2, port: 3, db: 4, password: 5 } diff --git a/actioncable/test/test_helper.rb b/actioncable/test/test_helper.rb index 2f186b7193..ac7881c950 100644 --- a/actioncable/test/test_helper.rb +++ b/actioncable/test/test_helper.rb @@ -2,9 +2,9 @@ require "action_cable" require "active_support/testing/autorun" +require "active_support/testing/method_call_assertions" require "puma" -require "mocha/minitest" require "rack/mock" begin @@ -16,6 +16,8 @@ end Dir[File.expand_path("stubs/*.rb", __dir__)].each { |file| require file } class ActionCable::TestCase < ActiveSupport::TestCase + include ActiveSupport::Testing::MethodCallAssertions + def wait_for_async wait_for_executor Concurrent.global_io_executor end diff --git a/actioncable/test/worker_test.rb b/actioncable/test/worker_test.rb index bc1f3e415a..f7dc428441 100644 --- a/actioncable/test/worker_test.rb +++ b/actioncable/test/worker_test.rb @@ -2,7 +2,7 @@ require "test_helper" -class WorkerTest < ActiveSupport::TestCase +class WorkerTest < ActionCable::TestCase class Receiver attr_accessor :last_action diff --git a/actionmailer/CHANGELOG.md b/actionmailer/CHANGELOG.md index 6d91d4fbd6..1468a89e96 100644 --- a/actionmailer/CHANGELOG.md +++ b/actionmailer/CHANGELOG.md @@ -1,3 +1,20 @@ +* Allow call `assert_enqueued_email_with` with no block. + + Example: + ``` + def test_email + ContactMailer.welcome.deliver_later + assert_enqueued_email_with ContactMailer, :welcome + end + + def test_email_with_arguments + ContactMailer.welcome("Hello", "Goodbye").deliver_later + assert_enqueued_email_with ContactMailer, :welcome, args: ["Hello", "Goodbye"] + end + ``` + + *bogdanvlviv* + * Ensure mail gem is eager autoloaded when eager load is true to prevent thread deadlocks. *Samuel Cochran* @@ -6,6 +23,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/lib/action_mailer/test_helper.rb b/actionmailer/lib/action_mailer/test_helper.rb index 6906472660..a4751916af 100644 --- a/actionmailer/lib/action_mailer/test_helper.rb +++ b/actionmailer/lib/action_mailer/test_helper.rb @@ -60,7 +60,7 @@ module ActionMailer # # Note: This assertion is simply a shortcut for: # - # assert_emails 0 + # assert_emails 0, &block def assert_no_emails(&block) assert_emails 0, &block 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/actionmailer/test/test_helper_test.rb b/actionmailer/test/test_helper_test.rb index 8fdc687a8b..dcea23aabb 100644 --- a/actionmailer/test/test_helper_test.rb +++ b/actionmailer/test/test_helper_test.rb @@ -252,7 +252,16 @@ class TestHelperMailerTest < ActionMailer::TestCase end end - def test_assert_enqueued_email_with_args + def test_assert_enqueued_email_with_with_no_block + assert_nothing_raised do + silence_stream($stdout) do + TestHelperMailer.test.deliver_later + assert_enqueued_email_with TestHelperMailer, :test + end + end + end + + def test_assert_enqueued_email_with_with_args assert_nothing_raised do assert_enqueued_email_with TestHelperMailer, :test_args, args: ["some_email", "some_name"] do silence_stream($stdout) do @@ -262,7 +271,16 @@ class TestHelperMailerTest < ActionMailer::TestCase end end - def test_assert_enqueued_email_with_parameterized_args + def test_assert_enqueued_email_with_with_no_block_with_args + assert_nothing_raised do + silence_stream($stdout) do + TestHelperMailer.test_args("some_email", "some_name").deliver_later + assert_enqueued_email_with TestHelperMailer, :test_args, args: ["some_email", "some_name"] + end + end + end + + def test_assert_enqueued_email_with_with_parameterized_args assert_nothing_raised do assert_enqueued_email_with TestHelperMailer, :test_parameter_args, args: { all: "good" } do silence_stream($stdout) do @@ -271,6 +289,15 @@ class TestHelperMailerTest < ActionMailer::TestCase end end end + + def test_assert_enqueued_email_with_with_no_block_wiht_parameterized_args + assert_nothing_raised do + silence_stream($stdout) do + TestHelperMailer.with(all: "good").test_parameter_args.deliver_later + assert_enqueued_email_with TestHelperMailer, :test_parameter_args, args: { all: "good" } + end + end + end end class AnotherTestHelperMailerTest < ActionMailer::TestCase diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md index a13d9e1078..7645b2b0e7 100644 --- a/actionpack/CHANGELOG.md +++ b/actionpack/CHANGELOG.md @@ -1,4 +1,14 @@ -* Introduce a new error page to when the implict render page is accessed in the browser. +* Pass along arguments to underlying `get` method in `follow_redirect!` + + Now all arguments passed to `follow_redirect!` are passed to the underlying + `get` method. This for example allows to set custom headers for the + redirection request to the server. + + follow_redirect!(params: { foo: :bar }) + + *Remo Fritzsche* + +* Introduce a new error page to when the implicit render page is accessed in the browser. Now instead of showing an error page that with exception and backtraces we now show only one informative page. diff --git a/actionpack/lib/action_controller/metal/conditional_get.rb b/actionpack/lib/action_controller/metal/conditional_get.rb index 06b6a95ff8..4be4557e2c 100644 --- a/actionpack/lib/action_controller/metal/conditional_get.rb +++ b/actionpack/lib/action_controller/metal/conditional_get.rb @@ -235,7 +235,9 @@ module ActionController response.cache_control.merge!( max_age: seconds, public: options.delete(:public), - must_revalidate: options.delete(:must_revalidate) + must_revalidate: options.delete(:must_revalidate), + stale_while_revalidate: options.delete(:stale_while_revalidate), + stale_if_error: options.delete(:stale_if_error), ) options.delete(:private) diff --git a/actionpack/lib/action_controller/metal/http_authentication.rb b/actionpack/lib/action_controller/metal/http_authentication.rb index 01676f3237..a871ccd533 100644 --- a/actionpack/lib/action_controller/metal/http_authentication.rb +++ b/actionpack/lib/action_controller/metal/http_authentication.rb @@ -56,8 +56,9 @@ module ActionController # In your integration tests, you can do something like this: # # def test_access_granted_from_xml - # @request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials(users(:dhh).name, users(:dhh).password) - # get "/notes/1.xml" + # authorization = ActionController::HttpAuthentication::Basic.encode_credentials(users(:dhh).name, users(:dhh).password) + # + # get "/notes/1.xml", headers: { 'HTTP_AUTHORIZATION' => authorization } # # assert_equal 200, status # end @@ -389,10 +390,9 @@ module ActionController # In your integration tests, you can do something like this: # # def test_access_granted_from_xml - # get( - # "/notes/1.xml", nil, - # 'HTTP_AUTHORIZATION' => ActionController::HttpAuthentication::Token.encode_credentials(users(:dhh).token) - # ) + # authorization = ActionController::HttpAuthentication::Token.encode_credentials(users(:dhh).token) + # + # get "/notes/1.xml", headers: { 'HTTP_AUTHORIZATION' => authorization } # # assert_equal 200, status # 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/lib/action_controller/metal/strong_parameters.rb b/actionpack/lib/action_controller/metal/strong_parameters.rb index 46c0e80194..a6f395d33b 100644 --- a/actionpack/lib/action_controller/metal/strong_parameters.rb +++ b/actionpack/lib/action_controller/metal/strong_parameters.rb @@ -639,20 +639,18 @@ module ActionController # params = ActionController::Parameters.new(a: 1, b: 2, c: 3) # params.transform_values { |x| x * 2 } # # => <ActionController::Parameters {"a"=>2, "b"=>4, "c"=>6} permitted: false> - def transform_values(&block) - if block - new_instance_with_inherited_permitted_status( - @parameters.transform_values(&block) - ) - else - @parameters.transform_values - end + def transform_values + return to_enum(:transform_values) unless block_given? + new_instance_with_inherited_permitted_status( + @parameters.transform_values { |v| yield convert_value_to_parameters(v) } + ) end # Performs values transformation and returns the altered # <tt>ActionController::Parameters</tt> instance. - def transform_values!(&block) - @parameters.transform_values!(&block) + def transform_values! + return to_enum(:transform_values!) unless block_given? + @parameters.transform_values! { |v| yield convert_value_to_parameters(v) } self end diff --git a/actionpack/lib/action_dispatch/http/cache.rb b/actionpack/lib/action_dispatch/http/cache.rb index a8febc32b3..a7c7cfc1e5 100644 --- a/actionpack/lib/action_dispatch/http/cache.rb +++ b/actionpack/lib/action_dispatch/http/cache.rb @@ -202,13 +202,17 @@ module ActionDispatch self._cache_control = _cache_control + ", #{control[:extras].join(', ')}" end else - extras = control[:extras] + extras = control[:extras] max_age = control[:max_age] + stale_while_revalidate = control[:stale_while_revalidate] + stale_if_error = control[:stale_if_error] options = [] options << "max-age=#{max_age.to_i}" if max_age options << (control[:public] ? PUBLIC : PRIVATE) options << MUST_REVALIDATE if control[:must_revalidate] + options << "stale-while-revalidate=#{stale_while_revalidate.to_i}" if stale_while_revalidate + options << "stale-if-error=#{stale_if_error.to_i}" if stale_if_error options.concat(extras) if extras self._cache_control = options.join(", ") diff --git a/actionpack/lib/action_dispatch/journey/routes.rb b/actionpack/lib/action_dispatch/journey/routes.rb index 639c063495..c0377459d5 100644 --- a/actionpack/lib/action_dispatch/journey/routes.rb +++ b/actionpack/lib/action_dispatch/journey/routes.rb @@ -51,11 +51,12 @@ module ActionDispatch def ast @ast ||= begin asts = anchored_routes.map(&:ast) - Nodes::Or.new(asts) unless asts.empty? + Nodes::Or.new(asts) end end def simulator + return if ast.nil? @simulator ||= begin gtg = GTG::Builder.new(ast).transition_table GTG::Simulator.new(gtg) diff --git a/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb b/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb index 33edad8bd9..077a83b112 100644 --- a/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb +++ b/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb @@ -152,23 +152,13 @@ module ActionDispatch end def create_template(request, wrapper) - traces = wrapper.traces - - trace_to_show = "Application Trace" - if traces[trace_to_show].empty? && wrapper.rescue_template != "routing_error" - trace_to_show = "Full Trace" - end - - if source_to_show = traces[trace_to_show].first - source_to_show_id = source_to_show[:id] - end - DebugView.new([RESCUES_TEMPLATE_PATH], request: request, + exception_wrapper: wrapper, exception: wrapper.exception, - traces: traces, - show_source_idx: source_to_show_id, - trace_to_show: trace_to_show, + traces: wrapper.traces, + show_source_idx: wrapper.source_to_show_id, + trace_to_show: wrapper.trace_to_show, routes_inspector: routes_inspector(wrapper.exception), source_extracts: wrapper.source_extracts, line_number: wrapper.line_number, diff --git a/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb b/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb index f05c69137b..fb2b2bd3b0 100644 --- a/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb +++ b/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb @@ -31,11 +31,12 @@ module ActionDispatch "ActionController::MissingExactTemplate" => "missing_exact_template", ) - attr_reader :backtrace_cleaner, :exception, :line_number, :file + attr_reader :backtrace_cleaner, :exception, :wrapped_causes, :line_number, :file def initialize(backtrace_cleaner, exception) @backtrace_cleaner = backtrace_cleaner @exception = original_exception(exception) + @wrapped_causes = wrapped_causes_for(exception, backtrace_cleaner) expand_backtrace if exception.is_a?(SyntaxError) || exception.cause.is_a?(SyntaxError) end @@ -66,7 +67,11 @@ module ActionDispatch full_trace_with_ids = [] full_trace.each_with_index do |trace, idx| - trace_with_id = { id: idx, trace: trace } + trace_with_id = { + exception_object_id: @exception.object_id, + id: idx, + trace: trace + } if application_trace.include?(trace) application_trace_with_ids << trace_with_id @@ -99,6 +104,18 @@ module ActionDispatch end end + def trace_to_show + if traces["Application Trace"].empty? && rescue_template != "routing_error" + "Full Trace" + else + "Application Trace" + end + end + + def source_to_show_id + (traces[trace_to_show].first || {})[:id] + end + private def backtrace @@ -113,6 +130,16 @@ module ActionDispatch end end + def causes_for(exception) + return enum_for(__method__, exception) unless block_given? + + yield exception while exception = exception.cause + end + + def wrapped_causes_for(exception, backtrace_cleaner) + causes_for(exception).map { |cause| self.class.new(backtrace_cleaner, cause) } + end + def clean_backtrace(*args) if backtrace_cleaner backtrace_cleaner.clean(backtrace, *args) diff --git a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb index 4ea96196d3..df680c1c5f 100644 --- a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb +++ b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb @@ -25,7 +25,7 @@ module ActionDispatch # goes a step further than signed cookies in that encrypted cookies cannot # be altered or read by users. This is the default starting in Rails 4. # - # Configure your session store in <tt>config/initializers/session_store.rb</tt>: + # Configure your session store in an initializer: # # Rails.application.config.session_store :cookie_store, key: '_your_app_session' # diff --git a/actionpack/lib/action_dispatch/middleware/static.rb b/actionpack/lib/action_dispatch/middleware/static.rb index 8130bfe2e7..277074f216 100644 --- a/actionpack/lib/action_dispatch/middleware/static.rb +++ b/actionpack/lib/action_dispatch/middleware/static.rb @@ -41,7 +41,6 @@ module ActionDispatch rescue SystemCallError false end - } return ::Rack::Utils.escape_path(match).b end diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/_source.html.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/_source.html.erb index e7b913bbe4..88a8e6ad83 100644 --- a/actionpack/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/_source.html.erb @@ -1,6 +1,8 @@ -<% @source_extracts.each_with_index do |source_extract, index| %> +<% error_index = local_assigns[:error_index] || 0 %> + +<% source_extracts.each_with_index do |source_extract, index| %> <% if source_extract[:code] %> - <div class="source <%="hidden" if @show_source_idx != index%>" id="frame-source-<%=index%>"> + <div class="source <%= "hidden" if show_source_idx != index %>" id="frame-source-<%= error_index %>-<%= index %>"> <div class="info"> Extracted source (around line <strong>#<%= source_extract[:line_number] %></strong>): </div> diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb index ab57b11c7d..835ca8d260 100644 --- a/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb @@ -1,52 +1,62 @@ -<% names = @traces.keys %> +<% names = traces.keys %> +<% error_index = local_assigns[:error_index] || 0 %> <p><code>Rails.root: <%= defined?(Rails) && Rails.respond_to?(:root) ? Rails.root : "unset" %></code></p> -<div id="traces"> +<div id="traces-<%= error_index %>"> <% names.each do |name| %> <% - show = "show('#{name.gsub(/\s/, '-')}');" - hide = (names - [name]).collect {|hide_name| "hide('#{hide_name.gsub(/\s/, '-')}');"} + show = "show('#{name.gsub(/\s/, '-')}-#{error_index}');" + hide = (names - [name]).collect {|hide_name| "hide('#{hide_name.gsub(/\s/, '-')}-#{error_index}');"} %> <a href="#" onclick="<%= hide.join %><%= show %>; return false;"><%= name %></a> <%= '|' unless names.last == name %> <% end %> - <% @traces.each do |name, trace| %> - <div id="<%= name.gsub(/\s/, '-') %>" style="display: <%= (name == @trace_to_show) ? 'block' : 'none' %>;"> - <pre><code><% trace.each do |frame| %><a class="trace-frames" data-frame-id="<%= frame[:id] %>" href="#"><%= frame[:trace] %></a><br><% end %></code></pre> + <% traces.each do |name, trace| %> + <div id="<%= "#{name.gsub(/\s/, '-')}-#{error_index}" %>" style="display: <%= (name == trace_to_show) ? 'block' : 'none' %>;"> + <code style="font-size: 11px;"> + <% trace.each do |frame| %> + <a class="trace-frames trace-frames-<%= error_index %>" data-exception-object-id="<%= frame[:exception_object_id] %>" data-frame-id="<%= frame[:id] %>" href="#"> + <%= frame[:trace] %> + </a> + <br> + <% end %> + </code> </div> <% end %> <script type="text/javascript"> - var traceFrames = document.getElementsByClassName('trace-frames'); - var selectedFrame, currentSource = document.getElementById('frame-source-0'); - - // Add click listeners for all stack frames - for (var i = 0; i < traceFrames.length; i++) { - traceFrames[i].addEventListener('click', function(e) { - e.preventDefault(); - var target = e.target; - var frame_id = target.dataset.frameId; - - if (selectedFrame) { - selectedFrame.className = selectedFrame.className.replace("selected", ""); - } - - target.className += " selected"; - selectedFrame = target; - - // Change the extracted source code - changeSourceExtract(frame_id); - }); - - function changeSourceExtract(frame_id) { - var el = document.getElementById('frame-source-' + frame_id); - if (currentSource && el) { - currentSource.className += " hidden"; - el.className = el.className.replace(" hidden", ""); - currentSource = el; + (function() { + var traceFrames = document.getElementsByClassName('trace-frames-<%= error_index %>'); + var selectedFrame, currentSource = document.getElementById('frame-source-<%= error_index %>-0'); + + // Add click listeners for all stack frames + for (var i = 0; i < traceFrames.length; i++) { + traceFrames[i].addEventListener('click', function(e) { + e.preventDefault(); + var target = e.target; + var frame_id = target.dataset.frameId; + + if (selectedFrame) { + selectedFrame.className = selectedFrame.className.replace("selected", ""); + } + + target.className += " selected"; + selectedFrame = target; + + // Change the extracted source code + changeSourceExtract(frame_id); + }); + + function changeSourceExtract(frame_id) { + var el = document.getElementById('frame-source-<%= error_index %>-' + frame_id); + if (currentSource && el) { + currentSource.className += " hidden"; + el.className = el.className.replace(" hidden", ""); + currentSource = el; + } } } - } + })(); </script> </div> diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb index f154021ae6..bde26f46c2 100644 --- a/actionpack/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb @@ -10,7 +10,25 @@ <div id="container"> <h2><%= h @exception.message %></h2> - <%= render template: "rescues/_source" %> - <%= render template: "rescues/_trace" %> + <%= render "rescues/source", source_extracts: @source_extracts, show_source_idx: @show_source_idx, error_index: 0 %> + <%= render "rescues/trace", traces: @traces, trace_to_show: @trace_to_show, error_index: 0 %> + + <% if @exception.cause %> + <h2>Exception Causes</h2> + <% end %> + + <% @exception_wrapper.wrapped_causes.each.with_index(1) do |wrapper, index| %> + <div class="details"> + <a class="summary" href="#" style="color: #F0F0F0; text-decoration: none; background: #C52F24; border-bottom: none;" onclick="return toggle(<%= wrapper.exception.object_id %>)"> + <%= wrapper.exception.class.name %>: <%= h wrapper.exception.message %> + </a> + </div> + + <div id="<%= wrapper.exception.object_id %>" style="display: none;"> + <%= render "rescues/source", source_extracts: wrapper.source_extracts, show_source_idx: wrapper.source_to_show_id, error_index: index %> + <%= render "rescues/trace", traces: wrapper.traces, trace_to_show: wrapper.trace_to_show, error_index: index %> + </div> + <% end %> + <%= render template: "rescues/_request_and_response" %> </div> diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb index e1b129ccc5..056d99b03f 100644 --- a/actionpack/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb @@ -15,7 +15,7 @@ <% end %> </h2> - <%= render template: "rescues/_source" %> - <%= render template: "rescues/_trace" %> + <%= render "rescues/source", source_extracts: @source_extracts, show_source_idx: @show_source_idx %> + <%= render "rescues/trace", traces: @traces, trace_to_show: @trace_to_show %> <%= render template: "rescues/_request_and_response" %> </div> diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb index 2a65fd06ad..22eb6e9b4e 100644 --- a/actionpack/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb @@ -5,7 +5,7 @@ <div id="container"> <h2><%= h @exception.message %></h2> - <%= render template: "rescues/_source" %> - <%= render template: "rescues/_trace" %> + <%= render "rescues/source", source_extracts: @source_extracts, show_source_idx: @show_source_idx %> + <%= render "rescues/trace", traces: @traces, trace_to_show: @trace_to_show %> <%= render template: "rescues/_request_and_response" %> </div> diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb index 55dd5ddc7b..2b8f3f2a5e 100644 --- a/actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb @@ -14,7 +14,7 @@ </p> <% end %> - <%= render template: "rescues/_trace" %> + <%= render "rescues/trace", traces: @traces, trace_to_show: @trace_to_show %> <% if @routes_inspector %> <h2> diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb index 5060da9369..324ef1567a 100644 --- a/actionpack/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb @@ -11,10 +11,10 @@ </p> <pre><code><%= h @exception.message %></code></pre> - <%= render template: "rescues/_source" %> + <%= render "rescues/source", source_extracts: @source_extracts, show_source_idx: @show_source_idx %> <p><%= @exception.sub_template_message %></p> - <%= render template: "rescues/_trace" %> + <%= render "rescues/trace", traces: @traces, trace_to_show: @trace_to_show %> <%= render template: "rescues/_request_and_response" %> </div> diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb index f0398dc7b1..7637febd1c 100644 --- a/actionpack/lib/action_dispatch/testing/integration.rb +++ b/actionpack/lib/action_dispatch/testing/integration.rb @@ -50,10 +50,11 @@ module ActionDispatch # Follow a single redirect response. If the last response was not a # redirect, an exception will be raised. Otherwise, the redirect is - # performed on the location header. - def follow_redirect! + # performed on the location header. Any arguments are passed to the + # underlying call to `get`. + def follow_redirect!(**args) raise "not a redirect! #{status} #{status_message}" unless redirect? - get(response.location) + get(response.location, **args) status end end diff --git a/actionpack/lib/action_dispatch/testing/request_encoder.rb b/actionpack/lib/action_dispatch/testing/request_encoder.rb index 01246b7a2e..9889f61951 100644 --- a/actionpack/lib/action_dispatch/testing/request_encoder.rb +++ b/actionpack/lib/action_dispatch/testing/request_encoder.rb @@ -34,7 +34,7 @@ module ActionDispatch end def encode_params(params) - @param_encoder.call(params) + @param_encoder.call(params) if params end def self.parser(content_type) diff --git a/actionpack/test/controller/integration_test.rb b/actionpack/test/controller/integration_test.rb index 9cdf04b886..39ede1442a 100644 --- a/actionpack/test/controller/integration_test.rb +++ b/actionpack/test/controller/integration_test.rb @@ -349,6 +349,16 @@ class IntegrationProcessTest < ActionDispatch::IntegrationTest end end + def test_redirect_with_arguments + with_test_route_set do + get "/redirect" + follow_redirect! params: { foo: :bar } + + assert_response :ok + assert_equal "bar", request.parameters["foo"] + end + end + def test_xml_http_request_get with_test_route_set do get "/get", xhr: true @@ -1069,6 +1079,20 @@ class IntegrationRequestEncodersTest < ActionDispatch::IntegrationTest end end + def test_get_request_with_json_excludes_null_query_string + with_routing do |routes| + routes.draw do + ActiveSupport::Deprecation.silence do + get ":action" => FooController + end + end + + get "/foos_json", as: :json + + assert_equal "http://www.example.com/foos_json", request.url + end + end + private def post_to_foos(as:) with_routing do |routes| diff --git a/actionpack/test/controller/parameters/accessors_test.rb b/actionpack/test/controller/parameters/accessors_test.rb index 674b2c6266..68c7f2d9ea 100644 --- a/actionpack/test/controller/parameters/accessors_test.rb +++ b/actionpack/test/controller/parameters/accessors_test.rb @@ -190,6 +190,27 @@ class ParametersAccessorsTest < ActiveSupport::TestCase assert_not_predicate @params.transform_values { |v| v }, :permitted? end + test "transform_values converts hashes to parameters" do + @params.transform_values do |value| + assert_kind_of ActionController::Parameters, value + value + end + end + + test "transform_values without block yieds an enumerator" do + assert_kind_of Enumerator, @params.transform_values + end + + test "transform_values! converts hashes to parameters" do + @params.transform_values! do |value| + assert_kind_of ActionController::Parameters, value + end + end + + test "transform_values! without block yields an enumerator" do + assert_kind_of Enumerator, @params.transform_values! + end + test "value? returns true if the given value is present in the params" do params = ActionController::Parameters.new(city: "Chicago", state: "Illinois") assert params.value?("Chicago") diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb index 24c5761e41..6e3bd0596b 100644 --- a/actionpack/test/controller/render_test.rb +++ b/actionpack/test/controller/render_test.rb @@ -141,6 +141,16 @@ class TestController < ActionController::Base render action: "hello_world" end + def conditional_hello_with_expires_in_with_stale_while_revalidate + expires_in 1.minute, public: true, stale_while_revalidate: 5.minutes + render action: "hello_world" + end + + def conditional_hello_with_expires_in_with_stale_if_error + expires_in 1.minute, public: true, stale_if_error: 5.minutes + render action: "hello_world" + end + def conditional_hello_with_expires_in_with_public_with_more_keys expires_in 1.minute, :public => true, "s-maxage" => 5.hours render action: "hello_world" @@ -358,6 +368,16 @@ class ExpiresInRenderTest < ActionController::TestCase assert_equal "max-age=60, public, must-revalidate", @response.headers["Cache-Control"] end + def test_expires_in_header_with_stale_while_revalidate + get :conditional_hello_with_expires_in_with_stale_while_revalidate + assert_equal "max-age=60, public, stale-while-revalidate=300", @response.headers["Cache-Control"] + end + + def test_expires_in_header_with_stale_if_error + get :conditional_hello_with_expires_in_with_stale_if_error + assert_equal "max-age=60, public, stale-if-error=300", @response.headers["Cache-Control"] + end + def test_expires_in_header_with_additional_headers get :conditional_hello_with_expires_in_with_public_with_more_keys assert_equal "max-age=60, public, s-maxage=18000", @response.headers["Cache-Control"] 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/actionpack/test/controller/resources_test.rb b/actionpack/test/controller/resources_test.rb index 30bea64c55..3688fdbeee 100644 --- a/actionpack/test/controller/resources_test.rb +++ b/actionpack/test/controller/resources_test.rb @@ -66,7 +66,6 @@ class ResourcesTest < ActionController::TestCase member_methods.each_key do |action| assert_named_route "/messages/1/#{path_names[action] || action}", "#{action}_message_path", action: action, id: "1" end - end end end diff --git a/actionpack/test/controller/routing_test.rb b/actionpack/test/controller/routing_test.rb index 9d0a8b4f00..a7033b2d30 100644 --- a/actionpack/test/controller/routing_test.rb +++ b/actionpack/test/controller/routing_test.rb @@ -937,7 +937,6 @@ class RouteSetTest < ActiveSupport::TestCase @default_route_set ||= begin set = ActionDispatch::Routing::RouteSet.new set.draw do - ActiveSupport::Deprecation.silence do get "/:controller(/:action(/:id))" end @@ -1342,11 +1341,9 @@ class RouteSetTest < ActiveSupport::TestCase def test_namespace set.draw do - namespace "api" do get "inventory" => "products#inventory" end - end params = request_path_params("/api/inventory", method: :get) diff --git a/actionpack/test/controller/test_case_test.rb b/actionpack/test/controller/test_case_test.rb index 734da3de9c..dda2686a9b 100644 --- a/actionpack/test/controller/test_case_test.rb +++ b/actionpack/test/controller/test_case_test.rb @@ -223,6 +223,27 @@ XML assert_equal params.to_query, @response.body end + def test_params_round_trip + params = { "foo" => { "contents" => [{ "name" => "gorby", "id" => "123" }, { "name" => "puff", "d" => "true" }] } } + post :test_params, params: params.dup + + controller_info = { "controller" => "test_case_test/test", "action" => "test_params" } + assert_equal params.merge(controller_info), JSON.parse(@response.body) + end + + def test_handle_to_params + klass = Class.new do + def to_param + "bar" + end + end + + post :test_params, params: { foo: klass.new } + + assert_equal JSON.parse(@response.body)["foo"], "bar" + end + + def test_body_stream params = Hash[:page, { name: "page name" }, "some key", 123] @@ -380,7 +401,13 @@ XML process :test_xml_output, params: { response_as: "text/html" } # <area> auto-closes, so the <p> becomes a sibling - assert_select "root > area + p" + if defined?(JRUBY_VERSION) + # https://github.com/sparklemotion/nokogiri/issues/1653 + # HTML parser "fixes" "broken" markup in slightly different ways + assert_select "root > map > area + p" + else + assert_select "root > area + p" + end end def test_should_not_impose_childless_html_tags_in_xml diff --git a/actionpack/test/dispatch/debug_exceptions_test.rb b/actionpack/test/dispatch/debug_exceptions_test.rb index 045567ff83..44b79c0e5d 100644 --- a/actionpack/test/dispatch/debug_exceptions_test.rb +++ b/actionpack/test/dispatch/debug_exceptions_test.rb @@ -26,6 +26,18 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest raise StandardError.new "error in framework" end + def raise_nested_exceptions + begin + raise "First error" + rescue + begin + raise "Second error" + rescue + raise "Third error" + end + end + end + def call(env) env["action_dispatch.show_detailed_exceptions"] = @detailed req = ActionDispatch::Request.new(env) @@ -74,6 +86,8 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest end when %r{/framework_raises} method_that_raises + when %r{/nested_exceptions} + raise_nested_exceptions else raise "puke!" end @@ -440,8 +454,8 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest get "/original_syntax_error", headers: { "action_dispatch.backtrace_cleaner" => ActiveSupport::BacktraceCleaner.new } assert_response 500 - assert_select "#Application-Trace" do - assert_select "pre code", /syntax error, unexpected/ + assert_select "#Application-Trace-0" do + assert_select "code", /syntax error, unexpected/ end end @@ -454,9 +468,9 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest assert_select "#container h2", /^Missing template/ - assert_select "#Application-Trace" - assert_select "#Framework-Trace" - assert_select "#Full-Trace" + assert_select "#Application-Trace-0" + assert_select "#Framework-Trace-0" + assert_select "#Full-Trace-0" assert_select "h2", /Request/ end @@ -467,8 +481,8 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest get "/syntax_error_into_view", headers: { "action_dispatch.backtrace_cleaner" => ActiveSupport::BacktraceCleaner.new } assert_response 500 - assert_select "#Application-Trace" do - assert_select "pre code", /syntax error, unexpected/ + assert_select "#Application-Trace-0" do + assert_select "code", /syntax error, unexpected/ end end @@ -497,13 +511,13 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest end # assert application trace refers to line that calls method_that_raises is first - assert_select "#Application-Trace" do - assert_select "pre code a:first", %r{test/dispatch/debug_exceptions_test\.rb:\d+:in `call} + assert_select "#Application-Trace-0" do + assert_select "code a:first", %r{test/dispatch/debug_exceptions_test\.rb:\d+:in `call} end # assert framework trace that threw the error is first - assert_select "#Framework-Trace" do - assert_select "pre code a:first", /method_that_raises/ + assert_select "#Framework-Trace-0" do + assert_select "code a:first", /method_that_raises/ end end end @@ -523,4 +537,39 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest assert_response 500 assert_match(/puke/, body) end + + test "debug exceptions app shows all the nested exceptions in source view" do + @app = DevelopmentApp + Rails.stub :root, Pathname.new(".") do + cleaner = ActiveSupport::BacktraceCleaner.new.tap do |bc| + bc.add_silencer { |line| line !~ %r{test/dispatch/debug_exceptions_test.rb} } + end + + get "/nested_exceptions", headers: { "action_dispatch.backtrace_cleaner" => cleaner } + + # Assert correct error + assert_response 500 + assert_select "h2", /Third error/ + + # assert source view line shows the last error + assert_select "div.source:not(.hidden)" do + assert_select "pre .line.active", /raise "Third error"/ + end + + # assert application trace refers to line that raises the last exception + assert_select "#Application-Trace-0" do + assert_select "code a:first", %r{in `rescue in rescue in raise_nested_exceptions'} + end + + # assert the second application trace refers to the line that raises the second exception + assert_select "#Application-Trace-1" do + assert_select "code a:first", %r{in `rescue in raise_nested_exceptions'} + end + + # assert the third application trace refers to the line that raises the first exception + assert_select "#Application-Trace-2" do + assert_select "code a:first", %r{in `raise_nested_exceptions'} + end + end + end end diff --git a/actionpack/test/dispatch/exception_wrapper_test.rb b/actionpack/test/dispatch/exception_wrapper_test.rb index f6e70382a8..600280d6b3 100644 --- a/actionpack/test/dispatch/exception_wrapper_test.rb +++ b/actionpack/test/dispatch/exception_wrapper_test.rb @@ -108,11 +108,27 @@ module ActionDispatch wrapper = ExceptionWrapper.new(@cleaner, exception) assert_equal({ - "Application Trace" => [ id: 0, trace: "lib/file.rb:42:in `index'" ], - "Framework Trace" => [ id: 1, trace: "/gems/rack.rb:43:in `index'" ], + "Application Trace" => [ + exception_object_id: exception.object_id, + id: 0, + trace: "lib/file.rb:42:in `index'" + ], + "Framework Trace" => [ + exception_object_id: exception.object_id, + id: 1, + trace: "/gems/rack.rb:43:in `index'" + ], "Full Trace" => [ - { id: 0, trace: "lib/file.rb:42:in `index'" }, - { id: 1, trace: "/gems/rack.rb:43:in `index'" } + { + exception_object_id: exception.object_id, + id: 0, + trace: "lib/file.rb:42:in `index'" + }, + { + exception_object_id: exception.object_id, + id: 1, + trace: "/gems/rack.rb:43:in `index'" + } ] }, wrapper.traces) end diff --git a/actionpack/test/journey/route/definition/scanner_test.rb b/actionpack/test/journey/route/definition/scanner_test.rb index bcbe4388c3..092177d315 100644 --- a/actionpack/test/journey/route/definition/scanner_test.rb +++ b/actionpack/test/journey/route/definition/scanner_test.rb @@ -30,6 +30,12 @@ module ActionDispatch ["/~page", [[:SLASH, "/"], [:LITERAL, "~page"]]], ["/pa-ge", [[:SLASH, "/"], [:LITERAL, "pa-ge"]]], ["/:page", [[:SLASH, "/"], [:SYMBOL, ":page"]]], + ["/:page|*foo", [ + [:SLASH, "/"], + [:SYMBOL, ":page"], + [:OR, "|"], + [:STAR, "*foo"] + ]], ["/(:page)", [ [:SLASH, "/"], [:LPAREN, "("], diff --git a/actionpack/test/journey/router_test.rb b/actionpack/test/journey/router_test.rb index 183f421bcf..1f4e14aef6 100644 --- a/actionpack/test/journey/router_test.rb +++ b/actionpack/test/journey/router_test.rb @@ -493,6 +493,15 @@ module ActionDispatch assert_not called end + def test_eager_load_with_routes + get "/foo-bar", to: "foo#bar" + assert_nil router.eager_load! + end + + def test_eager_load_without_routes + assert_nil router.eager_load! + end + private def get(*args) diff --git a/actionview/CHANGELOG.md b/actionview/CHANGELOG.md index 2c1ca12043..6d45cc1d8a 100644 --- a/actionview/CHANGELOG.md +++ b/actionview/CHANGELOG.md @@ -1,3 +1,44 @@ +* Fix issue with `button_to`'s `to_form_params` + + `button_to` was throwing exception when invoked with `params` hash that + contains symbol and string keys. The reason for the exception was that + `to_form_params` was comparing the given symbol and string keys. + + The issue is fixed by turning all keys to strings inside + `to_form_params` before comparing them. + + *Georgi Georgiev* + +* Mark arrays of translations as trusted safe by using the `_html` suffix. + + Example: + + en: + foo_html: + - "One" + - "<strong>Two</strong>" + - "Three 👋 🙂" + + *Juan Broullon* + +* Add `year_format` option to date_select tag. This option makes it possible to customize year + names. Lambda should be passed to use this option. + + Example: + + date_select('user_birthday', '', start_year: 1998, end_year: 2000, year_format: ->year { "Heisei #{year - 1988}" }) + + The HTML produced: + + <select id="user_birthday__1i" name="user_birthday[(1i)]"> + <option value="1998">Heisei 10</option> + <option value="1999">Heisei 11</option> + <option value="2000">Heisei 12</option> + </select> + /* The rest is omitted */ + + *Koki Ryu* + * Fix JavaScript views rendering does not work with Firefox when using Content Security Policy. diff --git a/actionview/lib/action_view/helpers/date_helper.rb b/actionview/lib/action_view/helpers/date_helper.rb index 620e1e9f21..4de4fafde0 100644 --- a/actionview/lib/action_view/helpers/date_helper.rb +++ b/actionview/lib/action_view/helpers/date_helper.rb @@ -205,6 +205,7 @@ module ActionView # * <tt>:end_year</tt> - Set the end year for the year select. Default is <tt>Date.today.year + 5</tt> if # you are creating new record. While editing existing record, <tt>:end_year</tt> defaults to # the current selected year plus 5. + # * <tt>:year_format</tt> - Set format of years for year select. Lambda should be passed. # * <tt>:discard_day</tt> - Set to true if you don't want to show a day select. This includes the day # as a hidden field instead of showing a select field. Also note that this implicitly sets the day to be the # first of the given month in order to not create invalid dates like 31 February. @@ -275,6 +276,9 @@ module ActionView # # Generates a date select with custom prompts. # date_select("article", "written_on", prompt: { day: 'Select day', month: 'Select month', year: 'Select year' }) # + # # Generates a date select with custom year format. + # date_select("article", "written_on", year_format: ->(year) { "Heisei #{year - 1988}" }) + # # The selects are prepared for multi-parameter assignment to an Active Record object. # # Note: If the day is not included as an option but the month is, the day will be set to the 1st to ensure that @@ -668,8 +672,6 @@ module ActionView # <time datetime="2010-11-04T17:55:45+01:00">November 04, 2010 17:55</time> # time_tag Date.yesterday, 'Yesterday' # => # <time datetime="2010-11-03">Yesterday</time> - # time_tag Date.today, pubdate: true # => - # <time datetime="2010-11-04" pubdate="pubdate">November 04, 2010</time> # time_tag Date.today, datetime: Date.today.strftime('%G-W%V') # => # <time datetime="2010-W44">November 04, 2010</time> # @@ -850,7 +852,7 @@ module ActionView raise ArgumentError, "There are too many years options to be built. Are you sure you haven't mistyped something? You can provide the :max_years_allowed parameter." end - build_options_and_select(:year, val, options) + build_select(:year, build_year_options(val, options)) end end @@ -933,6 +935,21 @@ module ActionView end end + # Looks up year names by number. + # + # year_name(1998) # => 1998 + # + # If the <tt>:year_format</tt> option is passed: + # + # year_name(1998) # => "Heisei 10" + def year_name(number) + if year_format_lambda = @options[:year_format] + year_format_lambda.call(number) + else + number + end + end + def date_order @date_order ||= @options[:order] || translated_date_order end @@ -995,6 +1012,34 @@ module ActionView (select_options.join("\n") + "\n").html_safe end + # Build select option HTML for year. + # If <tt>year_format</tt> option is not passed + # build_year_options(1998, start: 1998, end: 2000) + # => "<option value="1998" selected="selected">1998</option> + # <option value="1999">1999</option> + # <option value="2000">2000</option>" + # + # If <tt>year_format</tt> option is passed + # build_year_options(1998, start: 1998, end: 2000, year_format: ->year { "Heisei #{ year - 1988 }" }) + # => "<option value="1998" selected="selected">Heisei 10</option> + # <option value="1999">Heisei 11</option> + # <option value="2000">Heisei 12</option>" + def build_year_options(selected, options = {}) + start = options.delete(:start) + stop = options.delete(:end) + step = options.delete(:step) + + select_options = [] + start.step(stop, step) do |value| + tag_options = { value: value } + tag_options[:selected] = "selected" if selected == value + text = year_name(value) + select_options << content_tag("option".freeze, text, tag_options) + end + + (select_options.join("\n") + "\n").html_safe + end + # Builds select tag from date type and HTML select options. # build_select(:month, "<option value="1">January</option>...") # => "<select id="post_written_on_2i" name="post[written_on(2i)]"> diff --git a/actionview/lib/action_view/helpers/form_helper.rb b/actionview/lib/action_view/helpers/form_helper.rb index 2d5c5684c1..07f3d98322 100644 --- a/actionview/lib/action_view/helpers/form_helper.rb +++ b/actionview/lib/action_view/helpers/form_helper.rb @@ -1658,6 +1658,7 @@ module ActionView @nested_child_index = {} @object_name, @object, @template, @options = object_name, object, template, options @default_options = @options ? @options.slice(:index, :namespace, :skip_default_ids, :allow_method_names_outside_object) : {} + @default_html_options = @default_options.except(:skip_default_ids, :allow_method_names_outside_object) convert_to_legacy_options(@options) diff --git a/actionview/lib/action_view/helpers/form_options_helper.rb b/actionview/lib/action_view/helpers/form_options_helper.rb index d02f641867..7884a8d997 100644 --- a/actionview/lib/action_view/helpers/form_options_helper.rb +++ b/actionview/lib/action_view/helpers/form_options_helper.rb @@ -820,7 +820,7 @@ module ActionView # # Please refer to the documentation of the base helper for details. def select(method, choices = nil, options = {}, html_options = {}, &block) - @template.select(@object_name, method, choices, objectify_options(options), @default_options.merge(html_options), &block) + @template.select(@object_name, method, choices, objectify_options(options), @default_html_options.merge(html_options), &block) end # Wraps ActionView::Helpers::FormOptionsHelper#collection_select for form builders: @@ -832,7 +832,7 @@ module ActionView # # Please refer to the documentation of the base helper for details. def collection_select(method, collection, value_method, text_method, options = {}, html_options = {}) - @template.collection_select(@object_name, method, collection, value_method, text_method, objectify_options(options), @default_options.merge(html_options)) + @template.collection_select(@object_name, method, collection, value_method, text_method, objectify_options(options), @default_html_options.merge(html_options)) end # Wraps ActionView::Helpers::FormOptionsHelper#grouped_collection_select for form builders: @@ -844,7 +844,7 @@ module ActionView # # Please refer to the documentation of the base helper for details. def grouped_collection_select(method, collection, group_method, group_label_method, option_key_method, option_value_method, options = {}, html_options = {}) - @template.grouped_collection_select(@object_name, method, collection, group_method, group_label_method, option_key_method, option_value_method, objectify_options(options), @default_options.merge(html_options)) + @template.grouped_collection_select(@object_name, method, collection, group_method, group_label_method, option_key_method, option_value_method, objectify_options(options), @default_html_options.merge(html_options)) end # Wraps ActionView::Helpers::FormOptionsHelper#time_zone_select for form builders: @@ -856,7 +856,7 @@ module ActionView # # Please refer to the documentation of the base helper for details. def time_zone_select(method, priority_zones = nil, options = {}, html_options = {}) - @template.time_zone_select(@object_name, method, priority_zones, objectify_options(options), @default_options.merge(html_options)) + @template.time_zone_select(@object_name, method, priority_zones, objectify_options(options), @default_html_options.merge(html_options)) end # Wraps ActionView::Helpers::FormOptionsHelper#collection_check_boxes for form builders: @@ -868,7 +868,7 @@ module ActionView # # Please refer to the documentation of the base helper for details. def collection_check_boxes(method, collection, value_method, text_method, options = {}, html_options = {}, &block) - @template.collection_check_boxes(@object_name, method, collection, value_method, text_method, objectify_options(options), @default_options.merge(html_options), &block) + @template.collection_check_boxes(@object_name, method, collection, value_method, text_method, objectify_options(options), @default_html_options.merge(html_options), &block) end # Wraps ActionView::Helpers::FormOptionsHelper#collection_radio_buttons for form builders: @@ -880,7 +880,7 @@ module ActionView # # Please refer to the documentation of the base helper for details. def collection_radio_buttons(method, collection, value_method, text_method, options = {}, html_options = {}, &block) - @template.collection_radio_buttons(@object_name, method, collection, value_method, text_method, objectify_options(options), @default_options.merge(html_options), &block) + @template.collection_radio_buttons(@object_name, method, collection, value_method, text_method, objectify_options(options), @default_html_options.merge(html_options), &block) end end end diff --git a/actionview/lib/action_view/helpers/sanitize_helper.rb b/actionview/lib/action_view/helpers/sanitize_helper.rb index 275a2dffb4..cb0c99c4cf 100644 --- a/actionview/lib/action_view/helpers/sanitize_helper.rb +++ b/actionview/lib/action_view/helpers/sanitize_helper.rb @@ -126,7 +126,7 @@ module ActionView attr_writer :full_sanitizer, :link_sanitizer, :white_list_sanitizer # Vendors the full, link and white list sanitizers. - # Provided strictly for compatibility and can be removed in Rails 5.1. + # Provided strictly for compatibility and can be removed in Rails 6. def sanitizer_vendor Rails::Html::Sanitizer end diff --git a/actionview/lib/action_view/helpers/tags/select.rb b/actionview/lib/action_view/helpers/tags/select.rb index 345484ba92..790721a0b7 100644 --- a/actionview/lib/action_view/helpers/tags/select.rb +++ b/actionview/lib/action_view/helpers/tags/select.rb @@ -8,7 +8,7 @@ module ActionView @choices = block_given? ? template_object.capture { yield || "" } : choices @choices = @choices.to_a if @choices.is_a?(Range) - @html_options = html_options.except(:skip_default_ids, :allow_method_names_outside_object) + @html_options = html_options super(object_name, method_name, template_object, options) end diff --git a/actionview/lib/action_view/helpers/translation_helper.rb b/actionview/lib/action_view/helpers/translation_helper.rb index d3cdab0d2f..ba82dcab3e 100644 --- a/actionview/lib/action_view/helpers/translation_helper.rb +++ b/actionview/lib/action_view/helpers/translation_helper.rb @@ -83,8 +83,11 @@ module ActionView end end translation = I18n.translate(scope_key_by_partial(key), html_safe_options.merge(raise: i18n_raise)) - - translation.respond_to?(:html_safe) ? translation.html_safe : translation + if translation.respond_to?(:map) + translation.map { |element| element.respond_to?(:html_safe) ? element.html_safe : element } + else + translation.respond_to?(:html_safe) ? translation.html_safe : translation + end else I18n.translate(scope_key_by_partial(key), options.merge(raise: i18n_raise)) end diff --git a/actionview/lib/action_view/helpers/url_helper.rb b/actionview/lib/action_view/helpers/url_helper.rb index cae62f2312..52bffaab84 100644 --- a/actionview/lib/action_view/helpers/url_helper.rb +++ b/actionview/lib/action_view/helpers/url_helper.rb @@ -634,7 +634,7 @@ module ActionView # suitable for use as the names and values of form input fields: # # to_form_params(name: 'David', nationality: 'Danish') - # # => [{name: :name, value: 'David'}, {name: 'nationality', value: 'Danish'}] + # # => [{name: 'name', value: 'David'}, {name: 'nationality', value: 'Danish'}] # # to_form_params(country: { name: 'Denmark' }) # # => [{name: 'country[name]', value: 'Denmark'}] @@ -666,7 +666,7 @@ module ActionView params.push(*to_form_params(value, array_prefix)) end else - params << { name: namespace, value: attribute.to_param } + params << { name: namespace.to_s, value: attribute.to_param } end params.sort_by { |pair| pair[:name] } diff --git a/actionview/test/template/date_helper_test.rb b/actionview/test/template/date_helper_test.rb index 4b4939d705..701e6c86fd 100644 --- a/actionview/test/template/date_helper_test.rb +++ b/actionview/test/template/date_helper_test.rb @@ -560,6 +560,15 @@ class DateHelperTest < ActionView::TestCase assert_dom_equal expected, select_year(Date.current, include_position: true, start_year: 2003, end_year: 2005) end + def test_select_year_with_custom_names + year_format_lambda = ->year { "Heisei #{ year - 1988 }" } + expected = %(<select id="date_year" name="date[year]">\n).dup + expected << %(<option value="2003">Heisei 15</option>\n<option value="2004">Heisei 16</option>\n<option value="2005">Heisei 17</option>\n) + expected << "</select>\n" + + assert_dom_equal expected, select_year(nil, start_year: 2003, end_year: 2005, year_format: year_format_lambda) + end + def test_select_hour expected = %(<select id="date_hour" name="date[hour]">\n).dup expected << %(<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08" selected="selected">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n) diff --git a/actionview/test/template/form_helper/form_with_test.rb b/actionview/test/template/form_helper/form_with_test.rb index 6b65d740eb..f07e494ee3 100644 --- a/actionview/test/template/form_helper/form_with_test.rb +++ b/actionview/test/template/form_helper/form_with_test.rb @@ -464,6 +464,23 @@ class FormWithActsLikeFormForTest < FormWithTest end end + def test_form_with_with_collection_select + post = Post.new + def post.active; false; end + form_with(model: post) do |f| + concat f.collection_select(:active, [true, false], :to_s, :to_s) + end + + expected = whole_form("/posts") do + "<select name='post[active]' id='post_active'>" \ + "<option value='true'>true</option>\n" \ + "<option selected='selected' value='false'>false</option>" \ + "</select>" + end + + assert_dom_equal expected, output_buffer + end + def test_form_with_with_collection_radio_buttons post = Post.new def post.active; false; end @@ -2347,13 +2364,4 @@ class FormWithActsLikeFormForTest < FormWithTest ensure I18n.locale = old_locale end - - def with_default_enforce_utf8(value) - old_value = ActionView::Helpers::FormTagHelper.default_enforce_utf8 - ActionView::Helpers::FormTagHelper.default_enforce_utf8 = value - - yield - ensure - ActionView::Helpers::FormTagHelper.default_enforce_utf8 = old_value - end end diff --git a/actionview/test/template/translation_helper_test.rb b/actionview/test/template/translation_helper_test.rb index f40595bf4d..e756348938 100644 --- a/actionview/test/template/translation_helper_test.rb +++ b/actionview/test/template/translation_helper_test.rb @@ -164,8 +164,11 @@ class TranslationHelperTest < ActiveSupport::TestCase assert_equal "<a>Other <One></a>", translate(:'translations.count_html', count: "<One>") end - def test_translation_returning_an_array_ignores_html_suffix - assert_equal ["foo", "bar"], translate(:'translations.array_html') + def test_translate_marks_array_of_translations_with_a_html_safe_suffix_as_safe_html + translate(:'translations.array_html').tap do |translated| + assert_equal %w( foo bar ), translated + assert translated.all?(&:html_safe?) + end end def test_translate_with_default_named_html diff --git a/actionview/test/template/url_helper_test.rb b/actionview/test/template/url_helper_test.rb index 08cb5dfea7..9d91dbb72b 100644 --- a/actionview/test/template/url_helper_test.rb +++ b/actionview/test/template/url_helper_test.rb @@ -77,11 +77,18 @@ class UrlHelperTest < ActiveSupport::TestCase def test_to_form_params_with_hash assert_equal( - [{ name: :name, value: "David" }, { name: :nationality, value: "Danish" }], + [{ name: "name", value: "David" }, { name: "nationality", value: "Danish" }], to_form_params(name: "David", nationality: "Danish") ) end + def test_to_form_params_with_hash_having_symbol_and_string_keys + assert_equal( + [{ name: "name", value: "David" }, { name: "nationality", value: "Danish" }], + to_form_params("name" => "David", :nationality => "Danish") + ) + end + def test_to_form_params_with_nested_hash assert_equal( [{ name: "country[name]", value: "Denmark" }], diff --git a/activejob/CHANGELOG.md b/activejob/CHANGELOG.md index dcb9d27f45..8526741383 100644 --- a/activejob/CHANGELOG.md +++ b/activejob/CHANGELOG.md @@ -1,3 +1,42 @@ +* Move `enqueue`/`enqueue_at` notifications to an around callback. + + Improves timing accuracy over the old after callback by including + time spent writing to the adapter's IO implementation. + + *Zach Kemp* + +* Allow `queue` option to `assert_no_enqueued_jobs`. + + Example: + ``` + def test_no_logging + assert_no_enqueued_jobs queue: 'default' do + LoggingJob.set(queue: :some_queue).perform_later + end + end + ``` + + *bogdanvlviv* + +* Allow call `assert_enqueued_with` with no block. + + Example: + ``` + def test_assert_enqueued_with + MyJob.perform_later(1,2,3) + assert_enqueued_with(job: MyJob, args: [1,2,3], queue: 'low') + + MyJob.set(wait_until: Date.tomorrow.noon).perform_later + assert_enqueued_with(job: MyJob, at: Date.tomorrow.noon) + end + ``` + + *bogdanvlviv* + +* Allow passing multiple exceptions to `retry_on`, and `discard_on`. + + *George Claghorn* + * Pass the error instance as the second parameter of block executed by `discard_on`. Fixes #32853. diff --git a/activejob/lib/active_job/base.rb b/activejob/lib/active_job/base.rb index 2b2a59e969..95b1062701 100644 --- a/activejob/lib/active_job/base.rb +++ b/activejob/lib/active_job/base.rb @@ -60,7 +60,6 @@ module ActiveJob #:nodoc: # * SerializationError - Error class for serialization errors. class Base include Core - include Serializers include QueueAdapter include QueueName include QueuePriority diff --git a/activejob/lib/active_job/exceptions.rb b/activejob/lib/active_job/exceptions.rb index 31bbb18d7f..1e57dbcb1c 100644 --- a/activejob/lib/active_job/exceptions.rb +++ b/activejob/lib/active_job/exceptions.rb @@ -30,8 +30,8 @@ module ActiveJob # class RemoteServiceJob < ActiveJob::Base # retry_on CustomAppException # defaults to 3s wait, 5 attempts # retry_on AnotherCustomAppException, wait: ->(executions) { executions * 2 } - # retry_on(YetAnotherCustomAppException) do |job, exception| - # ExceptionNotifier.caught(exception) + # retry_on(YetAnotherCustomAppException) do |job, error| + # ExceptionNotifier.caught(error) # end # retry_on ActiveRecord::Deadlocked, wait: 5.seconds, attempts: 3 # retry_on Net::OpenTimeout, wait: :exponentially_longer, attempts: 10 @@ -42,16 +42,16 @@ module ActiveJob # # Might raise Net::OpenTimeout when the remote service is down # end # end - def retry_on(exception, wait: 3.seconds, attempts: 5, queue: nil, priority: nil) - rescue_from exception do |error| + def retry_on(*exceptions, wait: 3.seconds, attempts: 5, queue: nil, priority: nil) + rescue_from(*exceptions) do |error| if executions < attempts - logger.error "Retrying #{self.class} in #{wait} seconds, due to a #{exception}. The original exception was #{error.cause.inspect}." + logger.error "Retrying #{self.class} in #{wait} seconds, due to a #{error.class}. The original exception was #{error.cause.inspect}." retry_job wait: determine_delay(wait), queue: queue, priority: priority else if block_given? yield self, error else - logger.error "Stopped retrying #{self.class} due to a #{exception}, which reoccurred on #{executions} attempts. The original exception was #{error.cause.inspect}." + logger.error "Stopped retrying #{self.class} due to a #{error.class}, which reoccurred on #{executions} attempts. The original exception was #{error.cause.inspect}." raise error end end @@ -67,8 +67,8 @@ module ActiveJob # # class SearchIndexingJob < ActiveJob::Base # discard_on ActiveJob::DeserializationError - # discard_on(CustomAppException) do |job, exception| - # ExceptionNotifier.caught(exception) + # discard_on(CustomAppException) do |job, error| + # ExceptionNotifier.caught(error) # end # # def perform(record) @@ -76,12 +76,12 @@ module ActiveJob # # Might raise CustomAppException for something domain specific # end # end - def discard_on(exception) - rescue_from exception do |error| + def discard_on(*exceptions) + rescue_from(*exceptions) do |error| if block_given? yield self, error else - logger.error "Discarded #{self.class} due to a #{exception}. The original exception was #{error.cause.inspect}." + logger.error "Discarded #{self.class} due to a #{error.class}. The original exception was #{error.cause.inspect}." end end end diff --git a/activejob/lib/active_job/logging.rb b/activejob/lib/active_job/logging.rb index 3312857ac7..9ffd60ad53 100644 --- a/activejob/lib/active_job/logging.rb +++ b/activejob/lib/active_job/logging.rb @@ -27,13 +27,13 @@ module ActiveJob end end - after_enqueue do |job| + around_enqueue do |job, block| if job.scheduled_at - ActiveSupport::Notifications.instrument "enqueue_at.active_job", - adapter: job.class.queue_adapter, job: job + ActiveSupport::Notifications.instrument("enqueue_at.active_job", + adapter: job.class.queue_adapter, job: job, &block) else - ActiveSupport::Notifications.instrument "enqueue.active_job", - adapter: job.class.queue_adapter, job: job + ActiveSupport::Notifications.instrument("enqueue.active_job", + adapter: job.class.queue_adapter, job: job, &block) end end end diff --git a/activejob/lib/active_job/serializers.rb b/activejob/lib/active_job/serializers.rb index df66e66659..a5d90f48b8 100644 --- a/activejob/lib/active_job/serializers.rb +++ b/activejob/lib/active_job/serializers.rb @@ -7,7 +7,6 @@ module ActiveJob # and to add new ones. It also has helpers to serialize/deserialize objects. module Serializers # :nodoc: extend ActiveSupport::Autoload - extend ActiveSupport::Concern autoload :ObjectSerializer autoload :SymbolSerializer diff --git a/activejob/lib/active_job/test_helper.rb b/activejob/lib/active_job/test_helper.rb index 1cd2c40c15..04cde28a96 100644 --- a/activejob/lib/active_job/test_helper.rb +++ b/activejob/lib/active_job/test_helper.rb @@ -159,11 +159,19 @@ module ActiveJob # end # end # + # It can be asserted that no jobs are enqueued to a specific queue: + # + # def test_no_logging + # assert_no_enqueued_jobs queue: 'default' do + # LoggingJob.set(queue: :some_queue).perform_later + # end + # end + # # Note: This assertion is simply a shortcut for: # # assert_enqueued_jobs 0, &block - def assert_no_enqueued_jobs(only: nil, except: nil, &block) - assert_enqueued_jobs 0, only: only, except: except, &block + def assert_no_enqueued_jobs(only: nil, except: nil, queue: nil, &block) + assert_enqueued_jobs 0, only: only, except: except, queue: queue, &block end # Asserts that the number of performed jobs matches the given number. @@ -286,7 +294,18 @@ module ActiveJob assert_performed_jobs 0, only: only, except: except, &block end - # Asserts that the job passed in the block has been enqueued with the given arguments. + # Asserts that the job has been enqueued with the given arguments. + # + # def test_assert_enqueued_with + # MyJob.perform_later(1,2,3) + # assert_enqueued_with(job: MyJob, args: [1,2,3], queue: 'low') + # + # MyJob.set(wait_until: Date.tomorrow.noon).perform_later + # assert_enqueued_with(job: MyJob, at: Date.tomorrow.noon) + # end + # + # If a block is passed, that block should cause the job to be + # enqueued with the given arguments. # # def test_assert_enqueued_with # assert_enqueued_with(job: MyJob, args: [1,2,3], queue: 'low') do @@ -298,14 +317,23 @@ module ActiveJob # end # end def assert_enqueued_with(job: nil, args: nil, at: nil, queue: nil) - original_enqueued_jobs_count = enqueued_jobs.count expected = { job: job, args: args, at: at, queue: queue }.compact serialized_args = serialize_args_for_assertion(expected) - yield - in_block_jobs = enqueued_jobs.drop(original_enqueued_jobs_count) - matching_job = in_block_jobs.find do |in_block_job| - serialized_args.all? { |key, value| value == in_block_job[key] } + + if block_given? + original_enqueued_jobs_count = enqueued_jobs.count + + yield + + jobs = enqueued_jobs.drop(original_enqueued_jobs_count) + else + jobs = enqueued_jobs end + + matching_job = jobs.find do |enqueued_job| + serialized_args.all? { |key, value| value == enqueued_job[key] } + end + assert matching_job, "No enqueued job found with #{expected}" instantiate_job(matching_job) end diff --git a/activejob/test/cases/exceptions_test.rb b/activejob/test/cases/exceptions_test.rb index 15938e3fc7..47d4e3c0c2 100644 --- a/activejob/test/cases/exceptions_test.rb +++ b/activejob/test/cases/exceptions_test.rb @@ -113,4 +113,22 @@ class ExceptionsTest < ActiveJob::TestCase end end end + + test "successfully retry job throwing one of two retryable exceptions" do + perform_enqueued_jobs do + RetryJob.perform_later "SecondRetryableErrorOfTwo", 3 + + assert_equal [ + "Raised SecondRetryableErrorOfTwo for the 1st time", + "Raised SecondRetryableErrorOfTwo for the 2nd time", + "Successfully completed job" ], JobBuffer.values + end + end + + test "discard job throwing one of two discardable exceptions" do + perform_enqueued_jobs do + RetryJob.perform_later "SecondDiscardableErrorOfTwo", 2 + assert_equal [ "Raised SecondDiscardableErrorOfTwo for the 1st time" ], JobBuffer.values + end + end end diff --git a/activejob/test/cases/logging_test.rb b/activejob/test/cases/logging_test.rb index 1f8c4a5573..a1107a07fd 100644 --- a/activejob/test/cases/logging_test.rb +++ b/activejob/test/cases/logging_test.rb @@ -45,6 +45,14 @@ class LoggingTest < ActiveSupport::TestCase ActiveJob::Base.logger = logger end + def subscribed + [].tap do |events| + ActiveSupport::Notifications.subscribed(-> (*args) { events << args }, /enqueue.*\.active_job/) do + yield + end + end + end + def test_uses_active_job_as_tag HelloJob.perform_later "Cristian" assert_match(/\[ActiveJob\]/, @logger.messages) @@ -86,8 +94,11 @@ class LoggingTest < ActiveSupport::TestCase end def test_enqueue_job_logging - HelloJob.perform_later "Cristian" + events = subscribed { HelloJob.perform_later "Cristian" } assert_match(/Enqueued HelloJob \(Job ID: .*?\) to .*?:.*Cristian/, @logger.messages) + assert_equal(events.count, 1) + key, * = events.first + assert_equal(key, "enqueue.active_job") end def test_perform_job_logging @@ -110,15 +121,21 @@ class LoggingTest < ActiveSupport::TestCase end def test_enqueue_at_job_logging - HelloJob.set(wait_until: 24.hours.from_now).perform_later "Cristian" + events = subscribed { HelloJob.set(wait_until: 24.hours.from_now).perform_later "Cristian" } assert_match(/Enqueued HelloJob \(Job ID: .*\) to .*? at.*Cristian/, @logger.messages) + assert_equal(events.count, 1) + key, * = events.first + assert_equal(key, "enqueue_at.active_job") rescue NotImplementedError skip end def test_enqueue_in_job_logging - HelloJob.set(wait: 2.seconds).perform_later "Cristian" + events = subscribed { HelloJob.set(wait: 2.seconds).perform_later "Cristian" } assert_match(/Enqueued HelloJob \(Job ID: .*\) to .*? at.*Cristian/, @logger.messages) + assert_equal(events.count, 1) + key, * = events.first + assert_equal(key, "enqueue_at.active_job") rescue NotImplementedError skip end diff --git a/activejob/test/cases/test_helper_test.rb b/activejob/test/cases/test_helper_test.rb index 66bcd8f3a0..d0a21a5da3 100644 --- a/activejob/test/cases/test_helper_test.rb +++ b/activejob/test/cases/test_helper_test.rb @@ -389,13 +389,91 @@ class EnqueuedJobsTest < ActiveJob::TestCase assert_match(/`:only` and `:except`/, error.message) end - def test_assert_enqueued_job + def test_assert_no_enqueued_jobs_with_queue_option + assert_nothing_raised do + assert_no_enqueued_jobs queue: :default do + HelloJob.set(queue: :other_queue).perform_later + LoggingJob.set(queue: :other_queue).perform_later + end + end + end + + def test_assert_no_enqueued_jobs_with_queue_option_failure + error = assert_raise ActiveSupport::TestCase::Assertion do + assert_no_enqueued_jobs queue: :other_queue do + HelloJob.set(queue: :other_queue).perform_later + end + end + + assert_match(/0 .* but 1/, error.message) + end + + def test_assert_no_enqueued_jobs_with_only_and_queue_option + assert_nothing_raised do + assert_no_enqueued_jobs only: HelloJob, queue: :some_queue do + HelloJob.set(queue: :other_queue).perform_later + HelloJob.set(queue: :other_queue).perform_later + LoggingJob.set(queue: :some_queue).perform_later + end + end + end + + def test_assert_no_enqueued_jobs_with_only_and_queue_option_failure + error = assert_raise ActiveSupport::TestCase::Assertion do + assert_no_enqueued_jobs only: HelloJob, queue: :some_queue do + HelloJob.set(queue: :other_queue).perform_later + HelloJob.set(queue: :some_queue).perform_later + LoggingJob.set(queue: :some_queue).perform_later + end + end + + assert_match(/0 .* but 1/, error.message) + end + + def test_assert_no_enqueued_jobs_with_except_and_queue_option + assert_nothing_raised do + assert_no_enqueued_jobs except: LoggingJob, queue: :some_queue do + HelloJob.set(queue: :other_queue).perform_later + HelloJob.set(queue: :other_queue).perform_later + LoggingJob.set(queue: :some_queue).perform_later + end + end + end + + def test_assert_no_enqueued_jobs_with_except_and_queue_option_failure + error = assert_raise ActiveSupport::TestCase::Assertion do + assert_no_enqueued_jobs except: LoggingJob, queue: :some_queue do + HelloJob.set(queue: :other_queue).perform_later + HelloJob.set(queue: :some_queue).perform_later + LoggingJob.set(queue: :some_queue).perform_later + end + end + + assert_match(/0 .* but 1/, error.message) + end + + def test_assert_no_enqueued_jobs_with_only_and_except_and_queue_option + error = assert_raise ArgumentError do + assert_no_enqueued_jobs only: HelloJob, except: HelloJob, queue: :some_queue do + HelloJob.set(queue: :other_queue).perform_later + end + end + + assert_match(/`:only` and `:except`/, error.message) + end + + def test_assert_enqueued_with assert_enqueued_with(job: LoggingJob, queue: "default") do LoggingJob.set(wait_until: Date.tomorrow.noon).perform_later end end - def test_assert_enqueued_job_returns + def test_assert_enqueued_with_with_no_block + LoggingJob.set(wait_until: Date.tomorrow.noon).perform_later + assert_enqueued_with(job: LoggingJob, queue: "default") + end + + def test_assert_enqueued_with_returns job = assert_enqueued_with(job: LoggingJob) do LoggingJob.set(wait_until: 5.minutes.from_now).perform_later(1, 2, 3) end @@ -406,13 +484,28 @@ class EnqueuedJobsTest < ActiveJob::TestCase assert_equal [1, 2, 3], job.arguments end - def test_assert_enqueued_job_failure + def test_assert_enqueued_with_with_no_block_returns + LoggingJob.set(wait_until: 5.minutes.from_now).perform_later(1, 2, 3) + job = assert_enqueued_with(job: LoggingJob) + + assert_instance_of LoggingJob, job + assert_in_delta 5.minutes.from_now, job.scheduled_at, 1 + assert_equal "default", job.queue_name + assert_equal [1, 2, 3], job.arguments + end + + def test_assert_enqueued_with_failure assert_raise ActiveSupport::TestCase::Assertion do assert_enqueued_with(job: LoggingJob, queue: "default") do NestedJob.perform_later end end + assert_raise ActiveSupport::TestCase::Assertion do + LoggingJob.perform_later + assert_enqueued_with(job: LoggingJob) {} + end + error = assert_raise ActiveSupport::TestCase::Assertion do assert_enqueued_with(job: NestedJob, queue: "low") do NestedJob.perform_later @@ -422,7 +515,21 @@ class EnqueuedJobsTest < ActiveJob::TestCase assert_equal 'No enqueued job found with {:job=>NestedJob, :queue=>"low"}', error.message end - def test_assert_enqueued_job_args + def test_assert_enqueued_with_with_no_block_failure + assert_raise ActiveSupport::TestCase::Assertion do + NestedJob.perform_later + assert_enqueued_with(job: LoggingJob, queue: "default") + end + + error = assert_raise ActiveSupport::TestCase::Assertion do + NestedJob.perform_later + assert_enqueued_with(job: NestedJob, queue: "low") + end + + assert_equal 'No enqueued job found with {:job=>NestedJob, :queue=>"low"}', error.message + end + + def test_assert_enqueued_with_args assert_raise ArgumentError do assert_enqueued_with(class: LoggingJob) do NestedJob.set(wait_until: Date.tomorrow.noon).perform_later @@ -430,20 +537,38 @@ class EnqueuedJobsTest < ActiveJob::TestCase end end - def test_assert_enqueued_job_with_at_option + def test_assert_enqueued_with_with_no_block_args + assert_raise ArgumentError do + NestedJob.set(wait_until: Date.tomorrow.noon).perform_later + assert_enqueued_with(class: LoggingJob) + end + end + + def test_assert_enqueued_with_with_at_option assert_enqueued_with(job: HelloJob, at: Date.tomorrow.noon) do HelloJob.set(wait_until: Date.tomorrow.noon).perform_later end end - def test_assert_enqueued_job_with_global_id_args + def test_assert_enqueued_with_with_no_block_with_at_option + HelloJob.set(wait_until: Date.tomorrow.noon).perform_later + assert_enqueued_with(job: HelloJob, at: Date.tomorrow.noon) + end + + def test_assert_enqueued_with_with_global_id_args ricardo = Person.new(9) assert_enqueued_with(job: HelloJob, args: [ricardo]) do HelloJob.perform_later(ricardo) end end - def test_assert_enqueued_job_failure_with_global_id_args + def test_assert_enqueued_with_with_no_block_with_global_id_args + ricardo = Person.new(9) + HelloJob.perform_later(ricardo) + assert_enqueued_with(job: HelloJob, args: [ricardo]) + end + + def test_assert_enqueued_with_failure_with_global_id_args ricardo = Person.new(9) wilma = Person.new(11) error = assert_raise ActiveSupport::TestCase::Assertion do @@ -455,7 +580,18 @@ class EnqueuedJobsTest < ActiveJob::TestCase assert_equal "No enqueued job found with {:job=>HelloJob, :args=>[#{wilma.inspect}]}", error.message end - def test_assert_enqueued_job_does_not_change_jobs_count + def test_assert_enqueued_with_failure_with_no_block_with_global_id_args + ricardo = Person.new(9) + wilma = Person.new(11) + error = assert_raise ActiveSupport::TestCase::Assertion do + HelloJob.perform_later(ricardo) + assert_enqueued_with(job: HelloJob, args: [wilma]) + end + + assert_equal "No enqueued job found with {:job=>HelloJob, :args=>[#{wilma.inspect}]}", error.message + end + + def test_assert_enqueued_with_does_not_change_jobs_count HelloJob.perform_later assert_enqueued_with(job: HelloJob) do HelloJob.perform_later @@ -463,6 +599,14 @@ class EnqueuedJobsTest < ActiveJob::TestCase assert_equal 2, queue_adapter.enqueued_jobs.count end + + def test_assert_enqueued_with_with_no_block_does_not_change_jobs_count + HelloJob.perform_later + HelloJob.perform_later + assert_enqueued_with(job: HelloJob) + + assert_equal 2, queue_adapter.enqueued_jobs.count + end end class PerformedJobsTest < ActiveJob::TestCase diff --git a/activejob/test/jobs/retry_job.rb b/activejob/test/jobs/retry_job.rb index a12c65015b..1383fffd7d 100644 --- a/activejob/test/jobs/retry_job.rb +++ b/activejob/test/jobs/retry_job.rb @@ -4,22 +4,29 @@ require_relative "../support/job_buffer" require "active_support/core_ext/integer/inflections" class DefaultsError < StandardError; end +class FirstRetryableErrorOfTwo < StandardError; end +class SecondRetryableErrorOfTwo < StandardError; end class LongWaitError < StandardError; end class ShortWaitTenAttemptsError < StandardError; end class ExponentialWaitTenAttemptsError < StandardError; end class CustomWaitTenAttemptsError < StandardError; end class CustomCatchError < StandardError; end class DiscardableError < StandardError; end +class FirstDiscardableErrorOfTwo < StandardError; end +class SecondDiscardableErrorOfTwo < StandardError; end class CustomDiscardableError < StandardError; end class RetryJob < ActiveJob::Base retry_on DefaultsError + retry_on FirstRetryableErrorOfTwo, SecondRetryableErrorOfTwo retry_on LongWaitError, wait: 1.hour, attempts: 10 retry_on ShortWaitTenAttemptsError, wait: 1.second, attempts: 10 retry_on ExponentialWaitTenAttemptsError, wait: :exponentially_longer, attempts: 10 retry_on CustomWaitTenAttemptsError, wait: ->(executions) { executions * 2 }, attempts: 10 retry_on(CustomCatchError) { |job, error| JobBuffer.add("Dealt with a job that failed to retry in a custom way after #{job.arguments.second} attempts. Message: #{error.message}") } + discard_on DiscardableError + discard_on FirstDiscardableErrorOfTwo, SecondDiscardableErrorOfTwo discard_on(CustomDiscardableError) { |job, error| JobBuffer.add("Dealt with a job that was discarded in a custom way. Message: #{error.message}") } def perform(raising, attempts) diff --git a/activejob/test/support/queue_classic/inline.rb b/activejob/test/support/queue_classic/inline.rb index ca3cd4581b..0695a34c27 100644 --- a/activejob/test/support/queue_classic/inline.rb +++ b/activejob/test/support/queue_classic/inline.rb @@ -1,22 +1,23 @@ # frozen_string_literal: true require "queue_classic" +require "active_support/core_ext/module/redefine_method" module QC class Queue - def enqueue(method, *args) + redefine_method(:enqueue) do |method, *args| receiver_str, _, message = method.rpartition(".") receiver = eval(receiver_str) receiver.send(message, *args) end - def enqueue_in(seconds, method, *args) + redefine_method(:enqueue_in) do |seconds, method, *args| receiver_str, _, message = method.rpartition(".") receiver = eval(receiver_str) receiver.send(message, *args) end - def enqueue_at(not_before, method, *args) + redefine_method(:enqueue_at) do |not_before, method, *args| receiver_str, _, message = method.rpartition(".") receiver = eval(receiver_str) receiver.send(message, *args) diff --git a/activejob/test/support/sneakers/inline.rb b/activejob/test/support/sneakers/inline.rb index 92b69ee3bc..e772c68c6e 100644 --- a/activejob/test/support/sneakers/inline.rb +++ b/activejob/test/support/sneakers/inline.rb @@ -1,11 +1,12 @@ # frozen_string_literal: true require "sneakers" +require "active_support/core_ext/module/redefine_method" module Sneakers module Worker module ClassMethods - def enqueue(msg) + redefine_method(:enqueue) do |msg| worker = new(nil, nil, {}) worker.work(*msg) end diff --git a/activemodel/CHANGELOG.md b/activemodel/CHANGELOG.md index 6b557a7cb1..8f80838a33 100644 --- a/activemodel/CHANGELOG.md +++ b/activemodel/CHANGELOG.md @@ -1,3 +1,27 @@ +* Allows configurable attribute name for `#has_secure_password`. This + still defaults to an attribute named 'password', causing no breaking + change. There is a new method `#authenticate_XXX` where XXX is the + configured attribute name, making the existing `#authenticate` now an + alias for this when the attribute is the default 'password'. + Example: + + class User < ActiveRecord::Base + has_secure_password :recovery_password, validations: false + end + + user = User.new() + user.recovery_password = "42password" + user.recovery_password_digest # => "$2a$04$iOfhwahFymCs5weB3BNH/uX..." + user.authenticate_recovery_password('42password') # => user + + *Unathi Chonco* + +* Add `config.active_model.i18n_full_message` in order to control whether + the `full_message` error format can be overridden at the attribute or model + level in the locale files. This is `false` by default. + + *Martin Larochelle* + * Rails 6 requires Ruby 2.4.1 or newer. *Jeremy Daer* diff --git a/activemodel/lib/active_model/attributes.rb b/activemodel/lib/active_model/attributes.rb index 7d44f7f2a3..5bf213d593 100644 --- a/activemodel/lib/active_model/attributes.rb +++ b/activemodel/lib/active_model/attributes.rb @@ -103,7 +103,7 @@ module ActiveModel def self.set_name_cache(name, value) const_name = "ATTR_#{name}" unless const_defined? const_name - const_set const_name, value.dup.freeze + const_set const_name, -value end end } diff --git a/activemodel/lib/active_model/dirty.rb b/activemodel/lib/active_model/dirty.rb index eaf8dfb223..093052a70c 100644 --- a/activemodel/lib/active_model/dirty.rb +++ b/activemodel/lib/active_model/dirty.rb @@ -304,7 +304,7 @@ module ActiveModel # Handles <tt>*_previous_change</tt> for +method_missing+. def attribute_previous_change(attr) - previous_changes[attr] if attribute_previously_changed?(attr) + previous_changes[attr] end # Handles <tt>*_will_change!</tt> for +method_missing+. diff --git a/activemodel/lib/active_model/errors.rb b/activemodel/lib/active_model/errors.rb index 275e3f1313..edc30ee64d 100644 --- a/activemodel/lib/active_model/errors.rb +++ b/activemodel/lib/active_model/errors.rb @@ -62,6 +62,11 @@ module ActiveModel CALLBACKS_OPTIONS = [:if, :unless, :on, :allow_nil, :allow_blank, :strict] MESSAGE_OPTIONS = [:message] + class << self + attr_accessor :i18n_full_message # :nodoc: + end + self.i18n_full_message = false + attr_reader :messages, :details # Pass in the instance of the object that is using the errors object. @@ -323,7 +328,7 @@ module ActiveModel # person.errors.added? :name, "is too long" # => false def added?(attribute, message = :invalid, options = {}) if message.is_a? Symbol - self.details[attribute].map { |e| e[:error] }.include? message + self.details[attribute.to_sym].map { |e| e[:error] }.include? message else message = message.call if message.respond_to?(:call) message = normalize_message(attribute, message, options) @@ -364,12 +369,51 @@ module ActiveModel # Returns a full message for a given attribute. # # person.errors.full_message(:name, 'is invalid') # => "Name is invalid" + # + # The `"%{attribute} %{message}"` error format can be overridden with either + # + # * <tt>activemodel.errors.models.person/contacts/addresses.attributes.street.format</tt> + # * <tt>activemodel.errors.models.person/contacts/addresses.format</tt> + # * <tt>activemodel.errors.models.person.attributes.name.format</tt> + # * <tt>activemodel.errors.models.person.format</tt> + # * <tt>errors.format</tt> def full_message(attribute, message) return message if attribute == :base + + if self.class.i18n_full_message && @base.class.respond_to?(:i18n_scope) + parts = attribute.to_s.split(".") + attribute_name = parts.pop + namespace = parts.join("/") unless parts.empty? + attributes_scope = "#{@base.class.i18n_scope}.errors.models" + + if namespace + defaults = @base.class.lookup_ancestors.map do |klass| + [ + :"#{attributes_scope}.#{klass.model_name.i18n_key}/#{namespace}.attributes.#{attribute_name}.format", + :"#{attributes_scope}.#{klass.model_name.i18n_key}/#{namespace}.format", + ] + end + else + defaults = @base.class.lookup_ancestors.map do |klass| + [ + :"#{attributes_scope}.#{klass.model_name.i18n_key}.attributes.#{attribute_name}.format", + :"#{attributes_scope}.#{klass.model_name.i18n_key}.format", + ] + end + end + + defaults.flatten! + else + defaults = [] + end + + defaults << :"errors.format" + defaults << "%{attribute} %{message}" + attr_name = attribute.to_s.tr(".", "_").humanize attr_name = @base.class.human_attribute_name(attribute, default: attr_name) - I18n.t(:"errors.format", - default: "%{attribute} %{message}", + I18n.t(defaults.shift, + default: defaults, attribute: attr_name, message: message) end diff --git a/activemodel/lib/active_model/railtie.rb b/activemodel/lib/active_model/railtie.rb index a9cdabba00..0ed70bd473 100644 --- a/activemodel/lib/active_model/railtie.rb +++ b/activemodel/lib/active_model/railtie.rb @@ -7,8 +7,14 @@ module ActiveModel class Railtie < Rails::Railtie # :nodoc: config.eager_load_namespaces << ActiveModel + config.active_model = ActiveSupport::OrderedOptions.new + initializer "active_model.secure_password" do ActiveModel::SecurePassword.min_cost = Rails.env.test? end + + initializer "active_model.i18n_full_message" do + ActiveModel::Errors.i18n_full_message = config.active_model.delete(:i18n_full_message) || false + end end end diff --git a/activemodel/lib/active_model/secure_password.rb b/activemodel/lib/active_model/secure_password.rb index 86f051f5ce..51d54f34f3 100644 --- a/activemodel/lib/active_model/secure_password.rb +++ b/activemodel/lib/active_model/secure_password.rb @@ -16,15 +16,16 @@ module ActiveModel module ClassMethods # Adds methods to set and authenticate against a BCrypt password. - # This mechanism requires you to have a +password_digest+ attribute. + # This mechanism requires you to have a +XXX_digest+ attribute. + # Where +XXX+ is the attribute name of your desired password. # # The following validations are added automatically: # * Password must be present on creation # * Password length should be less than or equal to 72 bytes - # * Confirmation of password (using a +password_confirmation+ attribute) + # * Confirmation of password (using a +XXX_confirmation+ attribute) # - # If password confirmation validation is not needed, simply leave out the - # value for +password_confirmation+ (i.e. don't provide a form field for + # If confirmation validation is not needed, simply leave out the + # value for +XXX_confirmation+ (i.e. don't provide a form field for # it). When this attribute has a +nil+ value, the validation will not be # triggered. # @@ -37,9 +38,10 @@ module ActiveModel # # Example using Active Record (which automatically includes ActiveModel::SecurePassword): # - # # Schema: User(name:string, password_digest:string) + # # Schema: User(name:string, password_digest:string, recovery_password_digest:string) # class User < ActiveRecord::Base # has_secure_password + # has_secure_password :recovery_password, validations: false # end # # user = User.new(name: 'david', password: '', password_confirmation: 'nomatch') @@ -48,11 +50,15 @@ module ActiveModel # user.save # => false, confirmation doesn't match # user.password_confirmation = 'mUc3m00RsqyRe' # user.save # => true + # user.recovery_password = "42password" + # user.recovery_password_digest # => "$2a$04$iOfhwahFymCs5weB3BNH/uXkTG65HR.qpW.bNhEjFP3ftli3o5DQC" + # user.save # => true # user.authenticate('notright') # => false # user.authenticate('mUc3m00RsqyRe') # => user + # user.authenticate_recovery_password('42password') # => user # User.find_by(name: 'david').try(:authenticate, 'notright') # => false # User.find_by(name: 'david').try(:authenticate, 'mUc3m00RsqyRe') # => user - def has_secure_password(options = {}) + def has_secure_password(attribute = :password, validations: true) # Load bcrypt gem only when has_secure_password is used. # This is to avoid ActiveModel (and by extension the entire framework) # being dependent on a binary library. @@ -63,9 +69,40 @@ module ActiveModel raise end - include InstanceMethodsOnActivation + attr_reader attribute + + define_method("#{attribute}=") do |unencrypted_password| + if unencrypted_password.nil? + self.send("#{attribute}_digest=", nil) + elsif !unencrypted_password.empty? + instance_variable_set("@#{attribute}", unencrypted_password) + cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST : BCrypt::Engine.cost + self.send("#{attribute}_digest=", BCrypt::Password.create(unencrypted_password, cost: cost)) + end + end + + define_method("#{attribute}_confirmation=") do |unencrypted_password| + instance_variable_set("@#{attribute}_confirmation", unencrypted_password) + end + + # Returns +self+ if the password is correct, otherwise +false+. + # + # class User < ActiveRecord::Base + # has_secure_password validations: false + # end + # + # user = User.new(name: 'david', password: 'mUc3m00RsqyRe') + # user.save + # user.authenticate_password('notright') # => false + # user.authenticate_password('mUc3m00RsqyRe') # => user + define_method("authenticate_#{attribute}") do |unencrypted_password| + attribute_digest = send("#{attribute}_digest") + BCrypt::Password.new(attribute_digest).is_password?(unencrypted_password) && self + end + + alias_method :authenticate, :authenticate_password if attribute == :password - if options.fetch(:validations, true) + if validations include ActiveModel::Validations # This ensures the model has a password by checking whether the password_digest @@ -73,57 +110,13 @@ module ActiveModel # when there is an error, the message is added to the password attribute instead # so that the error message will make sense to the end-user. validate do |record| - record.errors.add(:password, :blank) unless record.password_digest.present? + record.errors.add(attribute, :blank) unless record.send("#{attribute}_digest").present? end - validates_length_of :password, maximum: ActiveModel::SecurePassword::MAX_PASSWORD_LENGTH_ALLOWED - validates_confirmation_of :password, allow_blank: true + validates_length_of attribute, maximum: ActiveModel::SecurePassword::MAX_PASSWORD_LENGTH_ALLOWED + validates_confirmation_of attribute, allow_blank: true end end end - - module InstanceMethodsOnActivation - # Returns +self+ if the password is correct, otherwise +false+. - # - # class User < ActiveRecord::Base - # has_secure_password validations: false - # end - # - # user = User.new(name: 'david', password: 'mUc3m00RsqyRe') - # user.save - # user.authenticate('notright') # => false - # user.authenticate('mUc3m00RsqyRe') # => user - def authenticate(unencrypted_password) - BCrypt::Password.new(password_digest).is_password?(unencrypted_password) && self - end - - attr_reader :password - - # Encrypts the password into the +password_digest+ attribute, only if the - # new password is not empty. - # - # class User < ActiveRecord::Base - # has_secure_password validations: false - # end - # - # user = User.new - # user.password = nil - # user.password_digest # => nil - # user.password = 'mUc3m00RsqyRe' - # user.password_digest # => "$2a$10$4LEA7r4YmNHtvlAvHhsYAeZmk/xeUVtMTYqwIvYY76EW5GUqDiP4." - def password=(unencrypted_password) - if unencrypted_password.nil? - self.password_digest = nil - elsif !unencrypted_password.empty? - @password = unencrypted_password - cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST : BCrypt::Engine.cost - self.password_digest = BCrypt::Password.create(unencrypted_password, cost: cost) - end - end - - def password_confirmation=(unencrypted_password) - @password_confirmation = unencrypted_password - end - end end end diff --git a/activemodel/lib/active_model/type/boolean.rb b/activemodel/lib/active_model/type/boolean.rb index bcdbab0343..f6c6efbc87 100644 --- a/activemodel/lib/active_model/type/boolean.rb +++ b/activemodel/lib/active_model/type/boolean.rb @@ -20,6 +20,10 @@ module ActiveModel :boolean end + def serialize(value) # :nodoc: + cast(value) + end + private def cast_value(value) diff --git a/activemodel/lib/active_model/type/value.rb b/activemodel/lib/active_model/type/value.rb index a8ea6a2c22..b6914dd63c 100644 --- a/activemodel/lib/active_model/type/value.rb +++ b/activemodel/lib/active_model/type/value.rb @@ -90,6 +90,10 @@ module ActiveModel false end + def force_equality?(_value) # :nodoc: + false + end + def map(value) # :nodoc: yield value end diff --git a/activemodel/lib/active_model/validations/numericality.rb b/activemodel/lib/active_model/validations/numericality.rb index 31750ba78e..0478915be7 100644 --- a/activemodel/lib/active_model/validations/numericality.rb +++ b/activemodel/lib/active_model/validations/numericality.rb @@ -19,9 +19,11 @@ module ActiveModel end def validate_each(record, attr_name, value) - before_type_cast = :"#{attr_name}_before_type_cast" + came_from_user = :"#{attr_name}_came_from_user?" - raw_value = record.send(before_type_cast) if record.respond_to?(before_type_cast) && record.send(before_type_cast) != value + if record.respond_to?(came_from_user) && record.public_send(came_from_user) + raw_value = record.read_attribute_before_type_cast(attr_name) + end raw_value ||= value if record_attribute_changed_in_place?(record, attr_name) diff --git a/activemodel/test/cases/errors_test.rb b/activemodel/test/cases/errors_test.rb index 6ff3be1308..41ff6443fe 100644 --- a/activemodel/test/cases/errors_test.rb +++ b/activemodel/test/cases/errors_test.rb @@ -185,6 +185,12 @@ class ErrorsTest < ActiveModel::TestCase assert person.errors.added?(:name, :blank) end + test "added? returns true when string attribute is used with a symbol message" do + person = Person.new + person.errors.add(:name, :blank) + assert person.errors.added?("name", :blank) + end + test "added? handles proc messages" do person = Person.new message = Proc.new { "cannot be blank" } diff --git a/activemodel/test/cases/railtie_test.rb b/activemodel/test/cases/railtie_test.rb index ff5022e960..ab60285e2a 100644 --- a/activemodel/test/cases/railtie_test.rb +++ b/activemodel/test/cases/railtie_test.rb @@ -31,4 +31,24 @@ class RailtieTest < ActiveModel::TestCase assert_equal true, ActiveModel::SecurePassword.min_cost end + + test "i18n full message defaults to false" do + @app.initialize! + + assert_equal false, ActiveModel::Errors.i18n_full_message + end + + test "i18n full message can be disabled" do + @app.config.active_model.i18n_full_message = false + @app.initialize! + + assert_equal false, ActiveModel::Errors.i18n_full_message + end + + test "i18n full message can be enabled" do + @app.config.active_model.i18n_full_message = true + @app.initialize! + + assert_equal true, ActiveModel::Errors.i18n_full_message + end end diff --git a/activemodel/test/cases/secure_password_test.rb b/activemodel/test/cases/secure_password_test.rb index c347aa9b24..9ef1148be8 100644 --- a/activemodel/test/cases/secure_password_test.rb +++ b/activemodel/test/cases/secure_password_test.rb @@ -186,9 +186,16 @@ class SecurePasswordTest < ActiveModel::TestCase test "authenticate" do @user.password = "secret" + @user.recovery_password = "42password" - assert_not @user.authenticate("wrong") - assert @user.authenticate("secret") + assert_equal false, @user.authenticate("wrong") + assert_equal @user, @user.authenticate("secret") + + assert_equal false, @user.authenticate_password("wrong") + assert_equal @user, @user.authenticate_password("secret") + + assert_equal false, @user.authenticate_recovery_password("wrong") + assert_equal @user, @user.authenticate_recovery_password("42password") end test "Password digest cost defaults to bcrypt default cost when min_cost is false" do diff --git a/activemodel/test/cases/validations/i18n_validation_test.rb b/activemodel/test/cases/validations/i18n_validation_test.rb index 9cfe189d0e..1c62e750de 100644 --- a/activemodel/test/cases/validations/i18n_validation_test.rb +++ b/activemodel/test/cases/validations/i18n_validation_test.rb @@ -12,6 +12,9 @@ class I18nValidationTest < ActiveModel::TestCase I18n.load_path.clear I18n.backend = I18n::Backend::Simple.new I18n.backend.store_translations("en", errors: { messages: { custom: nil } }) + + @original_i18n_full_message = ActiveModel::Errors.i18n_full_message + ActiveModel::Errors.i18n_full_message = true end def teardown @@ -19,6 +22,7 @@ class I18nValidationTest < ActiveModel::TestCase I18n.load_path.replace @old_load_path I18n.backend = @old_backend I18n.backend.reload! + ActiveModel::Errors.i18n_full_message = @original_i18n_full_message end def test_full_message_encoding @@ -42,6 +46,61 @@ class I18nValidationTest < ActiveModel::TestCase assert_equal ["Field Name empty"], @person.errors.full_messages end + def test_errors_full_messages_doesnt_use_attribute_format_without_config + ActiveModel::Errors.i18n_full_message = false + + I18n.backend.store_translations("en", activemodel: { + errors: { models: { person: { attributes: { name: { format: "%{message}" } } } } } }) + + person = Person.new + assert_equal "Name cannot be blank", person.errors.full_message(:name, "cannot be blank") + assert_equal "Name test cannot be blank", person.errors.full_message(:name_test, "cannot be blank") + end + + def test_errors_full_messages_uses_attribute_format + ActiveModel::Errors.i18n_full_message = true + + I18n.backend.store_translations("en", activemodel: { + errors: { models: { person: { attributes: { name: { format: "%{message}" } } } } } }) + + person = Person.new + assert_equal "cannot be blank", person.errors.full_message(:name, "cannot be blank") + assert_equal "Name test cannot be blank", person.errors.full_message(:name_test, "cannot be blank") + end + + def test_errors_full_messages_uses_model_format + ActiveModel::Errors.i18n_full_message = true + + I18n.backend.store_translations("en", activemodel: { + errors: { models: { person: { format: "%{message}" } } } }) + + person = Person.new + assert_equal "cannot be blank", person.errors.full_message(:name, "cannot be blank") + assert_equal "cannot be blank", person.errors.full_message(:name_test, "cannot be blank") + end + + def test_errors_full_messages_uses_deeply_nested_model_attributes_format + ActiveModel::Errors.i18n_full_message = true + + I18n.backend.store_translations("en", activemodel: { + errors: { models: { 'person/contacts/addresses': { attributes: { street: { format: "%{message}" } } } } } }) + + person = Person.new + assert_equal "cannot be blank", person.errors.full_message(:'contacts/addresses.street', "cannot be blank") + assert_equal "Contacts/addresses country cannot be blank", person.errors.full_message(:'contacts/addresses.country', "cannot be blank") + end + + def test_errors_full_messages_uses_deeply_nested_model_model_format + ActiveModel::Errors.i18n_full_message = true + + I18n.backend.store_translations("en", activemodel: { + errors: { models: { 'person/contacts/addresses': { format: "%{message}" } } } }) + + person = Person.new + assert_equal "cannot be blank", person.errors.full_message(:'contacts/addresses.street', "cannot be blank") + assert_equal "cannot be blank", person.errors.full_message(:'contacts/addresses.country', "cannot be blank") + end + # ActiveModel::Validations # A set of common cases for ActiveModel::Validations message generation that diff --git a/activemodel/test/models/user.rb b/activemodel/test/models/user.rb index e98fd8a0a1..bb1b187694 100644 --- a/activemodel/test/models/user.rb +++ b/activemodel/test/models/user.rb @@ -7,6 +7,7 @@ class User define_model_callbacks :create has_secure_password + has_secure_password :recovery_password, validations: false - attr_accessor :password_digest + attr_accessor :password_digest, :recovery_password_digest end diff --git a/activemodel/test/models/visitor.rb b/activemodel/test/models/visitor.rb index 9da004ffcc..96bf3ef10a 100644 --- a/activemodel/test/models/visitor.rb +++ b/activemodel/test/models/visitor.rb @@ -8,5 +8,6 @@ class Visitor has_secure_password(validations: false) - attr_accessor :password_digest, :password_confirmation + attr_accessor :password_digest + attr_reader :password_confirmation end diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index dda7d19915..456f569718 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,38 @@ +* Don't impose primary key order if limit() has already been supplied. + + Fixes #23607 + + *Brian Christian* + +* Add environment & load_config dependency to `bin/rake db:seed` to enable + seed load in environments without Rails and custom DB configuration + + *Tobias Bielohlawek* + +* Fix default value for mysql time types with specified precision. + + *Nikolay Kondratyev* + +* Fix `touch` option to behave consistently with `Persistence#touch` method. + + *Ryuta Kamizono* + +* Migrations raise when duplicate column definition. + + Fixes #33024. + + *Federico Martinez* + +* Bump minimum SQLite version to 3.8 + + *Yasuo Honda* + +* Fix parent record should not get saved with duplicate children records. + + Fixes #32940. + + *Santosh Wadghule* + * Fix logic on disabling commit callbacks so they are not called unexpectedly when errors occur. *Brian Durand* @@ -23,9 +58,9 @@ *Bogdan Gusiev* -* Add custom prefix option to ActiveRecord::Store.store_accessor. +* Add custom prefix/suffix options to `ActiveRecord::Store.store_accessor`. - *Tan Huynh* + *Tan Huynh*, *Yukio Mizuta* * Rails 6 requires Ruby 2.4.1 or newer. diff --git a/activerecord/lib/active_record/aggregations.rb b/activerecord/lib/active_record/aggregations.rb index 27a641f05b..3250e29b82 100644 --- a/activerecord/lib/active_record/aggregations.rb +++ b/activerecord/lib/active_record/aggregations.rb @@ -3,8 +3,6 @@ module ActiveRecord # See ActiveRecord::Aggregations::ClassMethods for documentation module Aggregations - extend ActiveSupport::Concern - def initialize_dup(*) # :nodoc: @aggregation_cache = {} super @@ -225,6 +223,10 @@ module ActiveRecord def composed_of(part_id, options = {}) options.assert_valid_keys(:class_name, :mapping, :allow_nil, :constructor, :converter) + unless self < Aggregations + include Aggregations + end + name = part_id.id2name class_name = options[:class_name] || name.camelize mapping = options[:mapping] || [ name, name ] diff --git a/activerecord/lib/active_record/associations/alias_tracker.rb b/activerecord/lib/active_record/associations/alias_tracker.rb index 4f3893588e..272eede824 100644 --- a/activerecord/lib/active_record/associations/alias_tracker.rb +++ b/activerecord/lib/active_record/associations/alias_tracker.rb @@ -33,7 +33,7 @@ module ActiveRecord elsif join.is_a?(Arel::Nodes::Join) join.left.name == name ? 1 : 0 elsif join.is_a?(Hash) - join.fetch(name, 0) + join[name] else raise ArgumentError, "joins list should be initialized by list of Arel::Nodes::Join" end diff --git a/activerecord/lib/active_record/associations/association.rb b/activerecord/lib/active_record/associations/association.rb index ca8c7794e0..44596f4424 100644 --- a/activerecord/lib/active_record/associations/association.rb +++ b/activerecord/lib/active_record/associations/association.rb @@ -19,7 +19,6 @@ module ActiveRecord # HasManyThroughAssociation + ThroughAssociation class Association #:nodoc: attr_reader :owner, :target, :reflection - attr_accessor :inversed delegate :options, to: :reflection @@ -67,7 +66,7 @@ module ActiveRecord # # Note that if the target has not been loaded, it is not considered stale. def stale_target? - !inversed && loaded? && @stale_state != stale_state + !@inversed && loaded? && @stale_state != stale_state end # Sets the target of this association to <tt>\target</tt>, and the \loaded flag to +true+. @@ -98,23 +97,24 @@ module ActiveRecord # Set the inverse association, if possible def set_inverse_instance(record) - if invertible_for?(record) - inverse = record.association(inverse_reflection_for(record).name) - inverse.target = owner - inverse.inversed = true + if inverse = inverse_association_for(record) + inverse.inversed_from(owner) end record end # Remove the inverse association, if possible def remove_inverse_instance(record) - if invertible_for?(record) - inverse = record.association(inverse_reflection_for(record).name) - inverse.target = nil - inverse.inversed = false + if inverse = inverse_association_for(record) + inverse.inversed_from(nil) end end + def inversed_from(record) + self.target = record + @inversed = !!record + end + # Returns the class of the target. belongs_to polymorphic overrides this to look at the # polymorphic_type field on the owner. def klass @@ -240,6 +240,12 @@ module ActiveRecord end end + def inverse_association_for(record) + if invertible_for?(record) + record.association(inverse_reflection_for(record).name) + end + end + # Can be redefined by subclasses, notably polymorphic belongs_to # The record parameter is necessary to support polymorphic inverses as we must check for # the association in the specific class of the record. @@ -269,6 +275,7 @@ module ActiveRecord def build_record(attributes) reflection.build_association(attributes) do |record| initialize_attributes(record, attributes) + yield(record) if block_given? end end diff --git a/activerecord/lib/active_record/associations/belongs_to_association.rb b/activerecord/lib/active_record/associations/belongs_to_association.rb index c8716741b0..08f450278d 100644 --- a/activerecord/lib/active_record/associations/belongs_to_association.rb +++ b/activerecord/lib/active_record/associations/belongs_to_association.rb @@ -16,7 +16,7 @@ module ActiveRecord end end - def target=(record) + def inversed_from(record) replace_keys(record) super end @@ -42,6 +42,10 @@ module ActiveRecord update_counters(1) end + def target_changed? + owner.saved_change_to_attribute?(reflection.foreign_key) + end + private def replace(record) if record @@ -53,6 +57,8 @@ module ActiveRecord decrement_counters end + replace_keys(record) + self.target = record end @@ -77,19 +83,22 @@ module ActiveRecord def update_counters_on_replace(record) if require_counter_update? && different_target?(record) owner.instance_variable_set :@_after_replace_counter_called, true - record.increment!(reflection.counter_cache_column) + record.increment!(reflection.counter_cache_column, touch: reflection.options[:touch]) decrement_counters end end # Checks whether record is different to the current target, without loading it def different_target?(record) - record.id != owner._read_attribute(reflection.foreign_key) + record._read_attribute(primary_key(record)) != owner._read_attribute(reflection.foreign_key) end def replace_keys(record) - owner[reflection.foreign_key] = record ? - record._read_attribute(reflection.association_primary_key(record.class)) : nil + owner[reflection.foreign_key] = record ? record._read_attribute(primary_key(record)) : nil + end + + def primary_key(record) + reflection.association_primary_key(record.class) end def foreign_key_present? diff --git a/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb b/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb index 75b4c4481a..3fd2fb5f67 100644 --- a/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb +++ b/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb @@ -9,8 +9,11 @@ module ActiveRecord type.presence && type.constantize end - private + def target_changed? + super || owner.saved_change_to_attribute?(reflection.foreign_type) + end + private def replace_keys(record) super owner[reflection.foreign_type] = record ? record.class.polymorphic_name : nil diff --git a/activerecord/lib/active_record/associations/builder/belongs_to.rb b/activerecord/lib/active_record/associations/builder/belongs_to.rb index c161454c1a..4b6cb76081 100644 --- a/activerecord/lib/active_record/associations/builder/belongs_to.rb +++ b/activerecord/lib/active_record/associations/builder/belongs_to.rb @@ -36,7 +36,7 @@ module ActiveRecord::Associations::Builder # :nodoc: if (@_after_replace_counter_called ||= false) @_after_replace_counter_called = false - elsif saved_change_to_attribute?(foreign_key) && !new_record? + elsif association(reflection.name).target_changed? if reflection.polymorphic? model = attribute_in_database(reflection.foreign_type).try(:constantize) model_was = attribute_before_last_save(reflection.foreign_type).try(:constantize) @@ -49,14 +49,22 @@ module ActiveRecord::Associations::Builder # :nodoc: foreign_key = attribute_in_database foreign_key if foreign_key && model.respond_to?(:increment_counter) + foreign_key = counter_cache_target(reflection, model, foreign_key) model.increment_counter(cache_column, foreign_key) end if foreign_key_was && model_was.respond_to?(:decrement_counter) + foreign_key_was = counter_cache_target(reflection, model_was, foreign_key_was) model_was.decrement_counter(cache_column, foreign_key_was) end end end + + private + def counter_cache_target(reflection, model, foreign_key) + primary_key = reflection.association_primary_key(model) + model.unscoped.where!(primary_key => foreign_key) + end end end @@ -84,7 +92,8 @@ module ActiveRecord::Associations::Builder # :nodoc: else klass = association.klass end - old_record = klass.find_by(klass.primary_key => old_foreign_id) + primary_key = reflection.association_primary_key(klass) + old_record = klass.find_by(primary_key => old_foreign_id) if old_record if touch != true diff --git a/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb b/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb index 1981da11a2..e3070e0472 100644 --- a/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb +++ b/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb @@ -2,39 +2,6 @@ module ActiveRecord::Associations::Builder # :nodoc: class HasAndBelongsToMany # :nodoc: - class JoinTableResolver # :nodoc: - KnownTable = Struct.new :join_table - - class KnownClass # :nodoc: - def initialize(lhs_class, rhs_class_name) - @lhs_class = lhs_class - @rhs_class_name = rhs_class_name - @join_table = nil - end - - def join_table - @join_table ||= [@lhs_class.table_name, klass.table_name].sort.join("\0").gsub(/^(.*[._])(.+)\0\1(.+)/, '\1\2_\3').tr("\0", "_") - end - - private - - def klass - @lhs_class.send(:compute_type, @rhs_class_name) - end - end - - def self.build(lhs_class, name, options) - if options[:join_table] - KnownTable.new options[:join_table].to_s - else - class_name = options.fetch(:class_name) { - name.to_s.camelize.singularize - } - KnownClass.new lhs_class, class_name.to_s - end - end - end - attr_reader :lhs_model, :association_name, :options def initialize(association_name, lhs_model, options) @@ -44,8 +11,6 @@ module ActiveRecord::Associations::Builder # :nodoc: end def through_model - habtm = JoinTableResolver.build lhs_model, association_name, options - join_model = Class.new(ActiveRecord::Base) { class << self attr_accessor :left_model @@ -56,7 +21,9 @@ module ActiveRecord::Associations::Builder # :nodoc: end def self.table_name - table_name_resolver.join_table + # Table name needs to be resolved lazily + # because RHS class might not have been loaded + @table_name ||= table_name_resolver.call end def self.compute_type(class_name) @@ -86,7 +53,7 @@ module ActiveRecord::Associations::Builder # :nodoc: } join_model.name = "HABTM_#{association_name.to_s.camelize}" - join_model.table_name_resolver = habtm + join_model.table_name_resolver = -> { table_name } join_model.left_model = lhs_model join_model.add_left_association :left_side, anonymous_class: lhs_model @@ -117,6 +84,18 @@ module ActiveRecord::Associations::Builder # :nodoc: middle_options end + def table_name + if options[:join_table] + options[:join_table].to_s + else + class_name = options.fetch(:class_name) { + association_name.to_s.camelize.singularize + } + klass = lhs_model.send(:compute_type, class_name.to_s) + [lhs_model.table_name, klass.table_name].sort.join("\0").gsub(/^(.*[._])(.+)\0\1(.+)/, '\1\2_\3').tr("\0", "_") + end + end + def belongs_to_options(options) rhs_options = {} diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb index d61d105544..840d900bbc 100644 --- a/activerecord/lib/active_record/associations/collection_association.rb +++ b/activerecord/lib/active_record/associations/collection_association.rb @@ -105,9 +105,7 @@ module ActiveRecord if attributes.is_a?(Array) attributes.collect { |attr| build(attr, &block) } else - add_to_target(build_record(attributes)) do |record| - yield(record) if block_given? - end + add_to_target(build_record(attributes, &block)) end end @@ -360,15 +358,18 @@ module ActiveRecord if attributes.is_a?(Array) attributes.collect { |attr| _create_record(attr, raise, &block) } else + record = build_record(attributes, &block) transaction do - add_to_target(build_record(attributes)) do |record| - yield(record) if block_given? - insert_record(record, true, raise) { + result = nil + add_to_target(record) do + result = insert_record(record, true, raise) { @_was_loaded = loaded? @association_ids = nil } end + raise ActiveRecord::Rollback unless result end + record end end @@ -399,7 +400,7 @@ module ActiveRecord records.each { |record| callback(:before_remove, record) } delete_records(existing_records, method) if existing_records.any? - records.each { |record| target.delete(record) } + @target -= records records.each { |record| callback(:after_remove, record) } end @@ -446,7 +447,9 @@ module ActiveRecord end end - result && records + raise ActiveRecord::Rollback unless result + + records end def replace_on_target(record, index, skip_callbacks) diff --git a/activerecord/lib/active_record/associations/has_many_through_association.rb b/activerecord/lib/active_record/associations/has_many_through_association.rb index 59929b8c4e..617956c768 100644 --- a/activerecord/lib/active_record/associations/has_many_through_association.rb +++ b/activerecord/lib/active_record/associations/has_many_through_association.rb @@ -90,7 +90,7 @@ module ActiveRecord def build_record(attributes) ensure_not_nested - record = super(attributes) + record = super inverse = source_reflection.inverse_of if inverse diff --git a/activerecord/lib/active_record/associations/has_one_association.rb b/activerecord/lib/active_record/associations/has_one_association.rb index d211884135..390bfd8b08 100644 --- a/activerecord/lib/active_record/associations/has_one_association.rb +++ b/activerecord/lib/active_record/associations/has_one_association.rb @@ -106,7 +106,7 @@ module ActiveRecord end end - def _create_record(attributes, raise_error = false) + def _create_record(attributes, raise_error = false, &block) unless owner.persisted? raise ActiveRecord::RecordNotSaved, "You cannot call create unless the parent is saved" end diff --git a/activerecord/lib/active_record/associations/join_dependency.rb b/activerecord/lib/active_record/associations/join_dependency.rb index f88e383fe0..b76005b587 100644 --- a/activerecord/lib/active_record/associations/join_dependency.rb +++ b/activerecord/lib/active_record/associations/join_dependency.rb @@ -14,10 +14,8 @@ module ActiveRecord i[column.name] = column.alias } } - @name_and_alias_cache = tables.each_with_object({}) { |table, h| - h[table.node] = table.columns.map { |column| - [column.name, column.alias] - } + @columns_cache = tables.each_with_object({}) { |table, h| + h[table.node] = table.columns } end @@ -25,9 +23,8 @@ module ActiveRecord @tables.flat_map(&:column_aliases) end - # An array of [column_name, alias] pairs for the table def column_aliases(node) - @name_and_alias_cache[node] + @columns_cache[node] end def column_alias(node, column) @@ -67,42 +64,31 @@ module ActiveRecord end end - def initialize(base, table, associations, alias_tracker) - @alias_tracker = alias_tracker + def initialize(base, table, associations) tree = self.class.make_tree associations @join_root = JoinBase.new(base, table, build(tree, base)) - @join_root.children.each { |child| construct_tables! @join_root, child } end def reflections join_root.drop(1).map!(&:reflection) end - def join_constraints(joins_to_add, join_type) - joins = join_root.children.flat_map { |child| - make_join_constraints(join_root, child, join_type) - } + def join_constraints(joins_to_add, join_type, alias_tracker) + @alias_tracker = alias_tracker + + construct_tables!(join_root) + joins = make_join_constraints(join_root, join_type) joins.concat joins_to_add.flat_map { |oj| + construct_tables!(oj.join_root) if join_root.match? oj.join_root walk join_root, oj.join_root else - oj.join_root.children.flat_map { |child| - make_join_constraints(oj.join_root, child, join_type) - } + make_join_constraints(oj.join_root, join_type) end } end - def aliases - @aliases ||= Aliases.new join_root.each_with_index.map { |join_part, i| - columns = join_part.column_names.each_with_index.map { |column_name, j| - Aliases::Column.new column_name, "t#{i}_r#{j}" - } - Aliases::Table.new(join_part, columns) - } - end - def instantiate(result_set, &block) primary_key = aliases.column_alias(join_root, join_root.primary_key) @@ -127,35 +113,49 @@ module ActiveRecord result_set.each { |row_hash| parent_key = primary_key ? row_hash[primary_key] : row_hash parent = parents[parent_key] ||= join_root.instantiate(row_hash, column_aliases, &block) - construct(parent, join_root, row_hash, result_set, seen, model_cache, aliases) + construct(parent, join_root, row_hash, seen, model_cache) } end parents.values end + def apply_column_aliases(relation) + relation._select!(-> { aliases.columns }) + end + protected - attr_reader :alias_tracker, :base_klass, :join_root + attr_reader :join_root private + attr_reader :alias_tracker - def make_constraints(parent, child, tables, join_type) - chain = child.reflection.chain - foreign_table = parent.table - foreign_klass = parent.base_klass - child.join_constraints(foreign_table, foreign_klass, join_type, tables, chain) + def aliases + @aliases ||= Aliases.new join_root.each_with_index.map { |join_part, i| + columns = join_part.column_names.each_with_index.map { |column_name, j| + Aliases::Column.new column_name, "t#{i}_r#{j}" + } + Aliases::Table.new(join_part, columns) + } end - def make_outer_joins(parent, child) - join_type = Arel::Nodes::OuterJoin - make_join_constraints(parent, child, join_type, true) + def construct_tables!(join_root) + join_root.each_children do |parent, child| + child.tables = table_aliases_for(parent, child) + end end - def make_join_constraints(parent, child, join_type, aliasing = false) - tables = aliasing ? table_aliases_for(parent, child) : child.tables - joins = make_constraints(parent, child, tables, join_type) + def make_join_constraints(join_root, join_type) + join_root.children.flat_map do |child| + make_constraints(join_root, child, join_type) + end + end - joins.concat child.children.flat_map { |c| make_join_constraints(child, c, join_type, aliasing) } + def make_constraints(parent, child, join_type = Arel::Nodes::OuterJoin) + foreign_table = parent.table + foreign_klass = parent.base_klass + joins = child.join_constraints(foreign_table, foreign_klass, join_type, alias_tracker) + joins.concat child.children.flat_map { |c| make_constraints(child, c, join_type) } end def table_aliases_for(parent, node) @@ -168,13 +168,8 @@ module ActiveRecord } end - def construct_tables!(parent, node) - node.tables = table_aliases_for(parent, node) - node.children.each { |child| construct_tables! node, child } - end - def table_alias_for(reflection, parent, join) - name = "#{reflection.plural_name}_#{parent.table_name}" + name = reflection.alias_candidate(parent.table_name) join ? "#{name}_join" : name end @@ -183,8 +178,8 @@ module ActiveRecord [left.children.find { |node2| node1.match? node2 }, node1] }.partition(&:first) - ojs = missing.flat_map { |_, n| make_outer_joins left, n } - intersection.flat_map { |l, r| walk l, r }.concat ojs + joins = intersection.flat_map { |l, r| r.table = l.table; walk(l, r) } + joins.concat missing.flat_map { |_, n| make_constraints(left, n) } end def find_reflection(klass, name) @@ -202,11 +197,11 @@ module ActiveRecord raise EagerLoadPolymorphicError.new(reflection) end - JoinAssociation.new(reflection, build(right, reflection.klass), alias_tracker) + JoinAssociation.new(reflection, build(right, reflection.klass)) end end - def construct(ar_parent, parent, row, rs, seen, model_cache, aliases) + def construct(ar_parent, parent, row, seen, model_cache) return if ar_parent.nil? parent.children.each do |node| @@ -215,7 +210,7 @@ module ActiveRecord other.loaded! elsif ar_parent.association_cached?(node.reflection.name) model = ar_parent.association(node.reflection.name).target - construct(model, node, row, rs, seen, model_cache, aliases) + construct(model, node, row, seen, model_cache) next end @@ -227,25 +222,20 @@ module ActiveRecord next end - model = seen[ar_parent.object_id][node.base_klass][id] + model = seen[ar_parent.object_id][node][id] if model - construct(model, node, row, rs, seen, model_cache, aliases) + construct(model, node, row, seen, model_cache) else - model = construct_model(ar_parent, node, row, model_cache, id, aliases) - - if node.reflection.scope && - node.reflection.scope_for(node.base_klass.unscoped).readonly_value - model.readonly! - end + model = construct_model(ar_parent, node, row, model_cache, id) - seen[ar_parent.object_id][node.base_klass][id] = model - construct(model, node, row, rs, seen, model_cache, aliases) + seen[ar_parent.object_id][node][id] = model + construct(model, node, row, seen, model_cache) end end end - def construct_model(record, node, row, model_cache, id, aliases) + def construct_model(record, node, row, model_cache, id) other = record.association(node.reflection.name) model = model_cache[node][id] ||= @@ -259,6 +249,7 @@ module ActiveRecord other.target = model end + model.readonly! if node.readonly? model end end diff --git a/activerecord/lib/active_record/associations/join_dependency/join_association.rb b/activerecord/lib/active_record/associations/join_dependency/join_association.rb index c36386ec7e..4583d89cba 100644 --- a/activerecord/lib/active_record/associations/join_dependency/join_association.rb +++ b/activerecord/lib/active_record/associations/join_dependency/join_association.rb @@ -6,17 +6,14 @@ module ActiveRecord module Associations class JoinDependency # :nodoc: class JoinAssociation < JoinPart # :nodoc: - # The reflection of the association represented - attr_reader :reflection + attr_reader :reflection, :tables + attr_accessor :table - attr_accessor :tables - - def initialize(reflection, children, alias_tracker) + def initialize(reflection, children) super(reflection.klass, children) - @alias_tracker = alias_tracker - @reflection = reflection - @tables = nil + @reflection = reflection + @tables = nil end def match?(other) @@ -24,14 +21,13 @@ module ActiveRecord super && reflection == other.reflection end - def join_constraints(foreign_table, foreign_klass, join_type, tables, chain) - joins = [] - tables = tables.reverse + def join_constraints(foreign_table, foreign_klass, join_type, alias_tracker) + joins = [] # The chain starts with the target table, but we want to end with it here (makes # more sense in this context), so we reverse - chain.reverse_each do |reflection| - table = tables.shift + reflection.chain.reverse_each.with_index(1) do |reflection, i| + table = tables[-i] klass = reflection.klass constraint = reflection.build_join_constraint(table, foreign_table) @@ -54,12 +50,16 @@ module ActiveRecord joins end - def table - tables.first + def tables=(tables) + @tables = tables + @table = tables.first end - private - attr_reader :alias_tracker + def readonly? + return @readonly if defined?(@readonly) + + @readonly = reflection.scope && reflection.scope_for(base_klass.unscoped).readonly_value + end end end end diff --git a/activerecord/lib/active_record/associations/join_dependency/join_part.rb b/activerecord/lib/active_record/associations/join_dependency/join_part.rb index 2181f308bf..3ad72a3646 100644 --- a/activerecord/lib/active_record/associations/join_dependency/join_part.rb +++ b/activerecord/lib/active_record/associations/join_dependency/join_part.rb @@ -33,6 +33,13 @@ module ActiveRecord children.each { |child| child.each(&block) } end + def each_children(&block) + children.each do |child| + yield self, child + child.each_children(&block) + end + end + # An Arel::Table for the active_record def table raise NotImplementedError @@ -47,8 +54,8 @@ module ActiveRecord length = column_names_with_alias.length while index < length - column_name, alias_name = column_names_with_alias[index] - hash[column_name] = row[alias_name] + column = column_names_with_alias[index] + hash[column.name] = row[column.alias] index += 1 end diff --git a/activerecord/lib/active_record/associations/singular_association.rb b/activerecord/lib/active_record/associations/singular_association.rb index ead89bfe6c..cfab16a745 100644 --- a/activerecord/lib/active_record/associations/singular_association.rb +++ b/activerecord/lib/active_record/associations/singular_association.rb @@ -17,9 +17,8 @@ module ActiveRecord replace(record) end - def build(attributes = {}) - record = build_record(attributes) - yield(record) if block_given? + def build(attributes = {}, &block) + record = build_record(attributes, &block) set_new_record(record) record end @@ -62,9 +61,8 @@ module ActiveRecord replace(record) end - def _create_record(attributes, raise_error = false) - record = build_record(attributes) - yield(record) if block_given? + def _create_record(attributes, raise_error = false, &block) + record = build_record(attributes, &block) saved = record.save set_new_record(record) raise RecordInvalid.new(record) if !saved && raise_error diff --git a/activerecord/lib/active_record/associations/through_association.rb b/activerecord/lib/active_record/associations/through_association.rb index 5afb0bc068..15e6565e69 100644 --- a/activerecord/lib/active_record/associations/through_association.rb +++ b/activerecord/lib/active_record/associations/through_association.rb @@ -114,7 +114,7 @@ module ActiveRecord attributes[inverse.foreign_key] = target.id end - super(attributes) + super end end end diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb index 83b5a5e698..e4b8b1a330 100644 --- a/activerecord/lib/active_record/attribute_methods.rb +++ b/activerecord/lib/active_record/attribute_methods.rb @@ -26,7 +26,7 @@ module ActiveRecord def self.set_name_cache(name, value) const_name = "ATTR_#{name}" unless const_defined? const_name - const_set const_name, value.dup.freeze + const_set const_name, -value end end } diff --git a/activerecord/lib/active_record/autosave_association.rb b/activerecord/lib/active_record/autosave_association.rb index 9575cc24c8..a405f05e0b 100644 --- a/activerecord/lib/active_record/autosave_association.rb +++ b/activerecord/lib/active_record/autosave_association.rb @@ -392,7 +392,7 @@ module ActiveRecord records -= records_to_destroy end - records.each do |record| + records.each_with_index do |record, index| next if record.destroyed? saved = true @@ -401,9 +401,11 @@ module ActiveRecord if autosave saved = association.insert_record(record, false) elsif !reflection.nested? - association_saved = association.insert_record(record) if reflection.validate? - saved = association_saved + valid = association_valid?(reflection, record, index) + saved = valid ? association.insert_record(record, false) : false + else + association.insert_record(record) end end elsif autosave diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 7ab9160265..5169f312f5 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -288,6 +288,7 @@ module ActiveRecord #:nodoc: extend Enum extend Delegation::DelegateCache extend CollectionCacheKey + extend Aggregations::ClassMethods include Core include DatabaseConfigurations @@ -314,7 +315,6 @@ module ActiveRecord #:nodoc: include ActiveModel::SecurePassword include AutosaveAssociation include NestedAttributes - include Aggregations include Transactions include TouchLater include NoTouching diff --git a/activerecord/lib/active_record/callbacks.rb b/activerecord/lib/active_record/callbacks.rb index fd6819d08f..b6852bfc71 100644 --- a/activerecord/lib/active_record/callbacks.rb +++ b/activerecord/lib/active_record/callbacks.rb @@ -128,7 +128,7 @@ module ActiveRecord # end # end # - # So you specify the object you want messaged on a given callback. When that callback is triggered, the object has + # So you specify the object you want to be messaged on a given callback. When that callback is triggered, the object has # a method by the name of the callback messaged. You can make these callbacks more flexible by passing in other # initialization data such as the name of the attribute to work with: # @@ -318,6 +318,10 @@ module ActiveRecord _run_touch_callbacks { super } end + def increment!(*, touch: nil) # :nodoc: + touch ? _run_touch_callbacks { super } : super + end + private def create_or_update(*) diff --git a/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb b/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb index 25622e34c8..8aeb934ec2 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb @@ -110,12 +110,7 @@ module ActiveRecord if @query_cache[sql].key?(binds) ActiveSupport::Notifications.instrument( "sql.active_record", - sql: sql, - binds: binds, - type_casted_binds: -> { type_casted_binds(binds) }, - name: name, - connection_id: object_id, - cached: true, + cache_notification_info(sql, name, binds) ) @query_cache[sql][binds] else @@ -125,6 +120,19 @@ module ActiveRecord end end + # Database adapters can override this method to + # provide custom cache information. + def cache_notification_info(sql, name, binds) + { + sql: sql, + binds: binds, + type_casted_binds: -> { type_casted_binds(binds) }, + name: name, + connection_id: object_id, + cached: true + } + end + # If arel is locked this is a SELECT ... FOR UPDATE or somesuch. Such # queries should not be cached. def locked?(arel) diff --git a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb index aec5fa6ba1..98b1348135 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb @@ -130,6 +130,7 @@ module ActiveRecord end def quoted_time(value) # :nodoc: + value = value.change(year: 2000, month: 1, day: 1) quoted_date(value).sub(/\A\d\d\d\d-\d\d-\d\d /, "") end diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index 5f090d16cd..582ac516c7 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -356,8 +356,12 @@ module ActiveRecord type = type.to_sym if type options = options.dup - if @columns_hash[name] && @columns_hash[name].primary_key? - raise ArgumentError, "you can't redefine the primary key column '#{name}'. To define a custom primary key, pass { id: false } to create_table." + if @columns_hash[name] + if @columns_hash[name].primary_key? + raise ArgumentError, "you can't redefine the primary key column '#{name}'. To define a custom primary key, pass { id: false } to create_table." + else + raise ArgumentError, "you can't define an already defined column '#{name}'." + end end index_options = options.delete(:index) diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb index 07acb5425e..284b38ed7b 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -558,17 +558,6 @@ module ActiveRecord @max_allowed_packet ||= (show_variable("max_allowed_packet") - bytes_margin) end - def with_multi_statements - previous_flags = @config[:flags] - @config[:flags] = Mysql2::Client::MULTI_STATEMENTS - reconnect! - - yield - ensure - @config[:flags] = previous_flags - reconnect! - end - def initialize_type_map(m = type_map) super diff --git a/activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb b/activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb index 4106ce01be..d89eeb7f54 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb @@ -62,6 +62,42 @@ module ActiveRecord @connection.abandon_results! end + def supports_set_server_option? + @connection.respond_to?(:set_server_option) + end + + def multi_statements_enabled?(flags) + if flags.is_a?(Array) + flags.include?("MULTI_STATEMENTS") + else + (flags & Mysql2::Client::MULTI_STATEMENTS) != 0 + end + end + + def with_multi_statements + previous_flags = @config[:flags] + + unless multi_statements_enabled?(previous_flags) + if supports_set_server_option? + @connection.set_server_option(Mysql2::Client::OPTION_MULTI_STATEMENTS_ON) + else + @config[:flags] = Mysql2::Client::MULTI_STATEMENTS + reconnect! + end + end + + yield + ensure + unless multi_statements_enabled?(previous_flags) + if supports_set_server_option? + @connection.set_server_option(Mysql2::Client::OPTION_MULTI_STATEMENTS_OFF) + else + @config[:flags] = previous_flags + reconnect! + end + end + end + def exec_stmt_and_free(sql, name, binds, cache_stmt: false) # make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been # made since we established the connection diff --git a/activerecord/lib/active_record/connection_adapters/mysql/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/mysql/schema_statements.rb index ce50590651..2087938d7c 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql/schema_statements.rb @@ -80,8 +80,8 @@ module ActiveRecord def new_column_from_field(table_name, field) type_metadata = fetch_type_metadata(field[:Type], field[:Extra]) - if type_metadata.type == :datetime && /\ACURRENT_TIMESTAMP(?:\(\))?\z/i.match?(field[:Default]) - default, default_function = nil, "CURRENT_TIMESTAMP" + if type_metadata.type == :datetime && /\ACURRENT_TIMESTAMP(?:\([0-6]?\))?\z/i.match?(field[:Default]) + default, default_function = nil, field[:Default] else default, default_function = field[:Default], nil end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb index d6852082ac..26abeea7ed 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb @@ -66,6 +66,10 @@ module ActiveRecord deserialize(raw_old_value) != new_value end + def force_equality?(value) + value.is_a?(::Array) + end + private def type_cast_array(value, method) diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb index 6edb7cfd3c..d85f9ab3ef 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb @@ -53,6 +53,10 @@ module ActiveRecord ::Range.new(new_begin, new_end, value.exclude_end?) end + def force_equality?(value) + value.is_a?(::Range) + end + private def type_cast_single(value) diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_definitions.rb index 6047217fcd..206b855a18 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_definitions.rb @@ -13,10 +13,10 @@ module ActiveRecord # t.timestamps # end # - # By default, this will use the +gen_random_uuid()+ function from the + # By default, this will use the <tt>gen_random_uuid()</tt> function from the # +pgcrypto+ extension. As that extension is only available in # PostgreSQL 9.4+, for earlier versions an explicit default can be set - # to use +uuid_generate_v4()+ from the +uuid-ossp+ extension instead: + # to use <tt>uuid_generate_v4()</tt> from the +uuid-ossp+ extension instead: # # create_table :stuffs, id: false do |t| # t.primary_key :id, :uuid, default: "uuid_generate_v4()" diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/sqlite3/schema_statements.rb index 58e5138e02..24e7bc65fa 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3/schema_statements.rb @@ -7,6 +7,10 @@ module ActiveRecord # Returns an array of indexes for the given table. def indexes(table_name) exec_query("PRAGMA index_list(#{quote_table_name(table_name)})", "SCHEMA").map do |row| + # Indexes SQLite creates implicitly for internal use start with "sqlite_". + # See https://www.sqlite.org/fileformat2.html#intschema + next if row["name"].starts_with?("sqlite_") + index_sql = query_value(<<-SQL, "SCHEMA") SELECT sql FROM sqlite_master @@ -40,7 +44,7 @@ module ActiveRecord where: where, orders: orders ) - end + end.compact end def create_schema_dumper(options) diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb index 544374586c..bee74dc33d 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb @@ -15,6 +15,8 @@ require "sqlite3" module ActiveRecord module ConnectionHandling # :nodoc: def sqlite3_connection(config) + config = config.symbolize_keys + # Require database. unless config[:database] raise ArgumentError, "No database file specified. Missing argument: database" @@ -31,7 +33,7 @@ module ActiveRecord db = SQLite3::Database.new( config[:database].to_s, - results_as_hash: true + config.merge(results_as_hash: true) ) db.busy_timeout(ConnectionAdapters::SQLite3Adapter.type_cast_config_to_integer(config[:timeout])) if config[:timeout] @@ -455,9 +457,6 @@ module ActiveRecord def copy_table_indexes(from, to, rename = {}) indexes(from).each do |index| name = index.name - # indexes sqlite creates for internal use start with `sqlite_` and - # don't need to be copied - next if name.starts_with?("sqlite_") if to == "a#{from}" name = "t#{name}" elsif from == "a#{to}" diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb index e1a0b2ecf8..df795df52e 100644 --- a/activerecord/lib/active_record/core.rb +++ b/activerecord/lib/active_record/core.rb @@ -139,11 +139,6 @@ module ActiveRecord end module ClassMethods # :nodoc: - def allocate - define_attribute_methods - super - end - def initialize_find_by_cache # :nodoc: @find_by_statement_cache = { true => Concurrent::Map.new, false => Concurrent::Map.new } end @@ -350,6 +345,28 @@ module ActiveRecord end ## + # Initializer used for instantiating objects that have been read from the + # database. +attributes+ should be an attributes object, and unlike the + # `initialize` method, no assignment calls are made per attribute. + # + # :nodoc: + def init_from_db(attributes) + init_internals + + @new_record = false + @attributes = attributes + + self.class.define_attribute_methods + + yield self if block_given? + + _run_find_callbacks + _run_initialize_callbacks + + self + end + + ## # :method: clone # Identical to Ruby's clone method. This is a "shallow" copy. Be warned that your attributes are not copied. # That means that modifying attributes of the clone will modify the original, since they will both point to the diff --git a/activerecord/lib/active_record/counter_cache.rb b/activerecord/lib/active_record/counter_cache.rb index ee4f818cbf..0d8748d7e6 100644 --- a/activerecord/lib/active_record/counter_cache.rb +++ b/activerecord/lib/active_record/counter_cache.rb @@ -47,8 +47,12 @@ module ActiveRecord reflection = child_class._reflections.values.find { |e| e.belongs_to? && e.foreign_key.to_s == foreign_key && e.options[:counter_cache].present? } counter_name = reflection.counter_cache_column - updates = { counter_name.to_sym => object.send(counter_association).count(:all) } - updates.merge!(touch_updates(touch)) if touch + updates = { counter_name => object.send(counter_association).count(:all) } + + if touch + names = touch if touch != true + updates.merge!(touch_attributes_with_time(*names)) + end unscoped.where(primary_key => object.id).update_all(updates) end @@ -68,8 +72,8 @@ module ActiveRecord # * +counters+ - A Hash containing the names of the fields # to update as keys and the amount to update the field by as values. # * <tt>:touch</tt> option - Touch timestamp columns when updating. - # Pass +true+ to touch +updated_at+ and/or +updated_on+. Pass a symbol to - # touch that column or an array of symbols to touch just those ones. + # If attribute names are passed, they are updated along with updated_at/on + # attributes. # # ==== Examples # @@ -107,11 +111,18 @@ module ActiveRecord end if touch - touch_updates = touch_updates(touch) + names = touch if touch != true + touch_updates = touch_attributes_with_time(*names) updates << sanitize_sql_for_assignment(touch_updates) unless touch_updates.empty? end - unscoped.where(primary_key => id).update_all updates.join(", ") + if id.is_a?(Relation) && self == id.klass + relation = id + else + relation = unscoped.where!(primary_key => id) + end + + relation.update_all updates.join(", ") end # Increment a numeric field by one, via a direct SQL update. @@ -165,13 +176,6 @@ module ActiveRecord def decrement_counter(counter_name, id, touch: nil) update_counters(id, counter_name => -1, touch: touch) end - - private - def touch_updates(touch) - touch = timestamp_attributes_for_update_in_model if touch == true - touch_time = current_time_from_proper_timezone - Array(touch).map { |column| [ column, touch_time ] }.to_h - end end private diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index 025201c20b..6ace973c29 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -831,10 +831,14 @@ module ActiveRecord write "== %s %s" % [text, "=" * length] end + # Takes a message argument and outputs it as is. + # A second boolean argument can be passed to specify whether to indent or not. def say(message, subitem = false) write "#{subitem ? " ->" : "--"} #{message}" end + # Outputs text along with how long it took to run its block. + # If the block returns an integer it assumes it is the number of rows affected. def say_with_time(message) say(message) result = nil @@ -844,6 +848,7 @@ module ActiveRecord result end + # Takes a block as an argument and suppresses any output generated by the block. def suppress_messages save, self.verbose = verbose, false yield diff --git a/activerecord/lib/active_record/no_touching.rb b/activerecord/lib/active_record/no_touching.rb index 754c891884..697076bdae 100644 --- a/activerecord/lib/active_record/no_touching.rb +++ b/activerecord/lib/active_record/no_touching.rb @@ -43,6 +43,13 @@ module ActiveRecord end end + # Returns +true+ if the class has +no_touching+ set, +false+ otherwise. + # + # Project.no_touching do + # Project.first.no_touching? # true + # Message.first.no_touching? # false + # end + # def no_touching? NoTouching.applied_to?(self.class) end diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb index a0d5f1ee9f..155d67fd8f 100644 --- a/activerecord/lib/active_record/persistence.rb +++ b/activerecord/lib/active_record/persistence.rb @@ -67,8 +67,18 @@ module ActiveRecord # how this "single-table" inheritance mapping is implemented. def instantiate(attributes, column_types = {}, &block) klass = discriminate_class_for_record(attributes) + instantiate_instance_of(klass, attributes, column_types, &block) + end + + # Given a class, an attributes hash, +instantiate_instance_of+ returns a + # new instance of the class. Accepts only keys as strings. + # + # This is private, don't call it. :) + # + # :nodoc: + def instantiate_instance_of(klass, attributes, column_types = {}, &block) attributes = klass.attributes_builder.build_from_database(attributes, column_types) - klass.allocate.init_with("attributes" => attributes, "new_record" => false, &block) + klass.allocate.init_from_db(attributes, &block) end # Updates an object (or multiple objects) and saves it to the database, if validations pass. diff --git a/activerecord/lib/active_record/querying.rb b/activerecord/lib/active_record/querying.rb index d33d36ac02..c84f3d0fbb 100644 --- a/activerecord/lib/active_record/querying.rb +++ b/activerecord/lib/active_record/querying.rb @@ -49,7 +49,12 @@ module ActiveRecord } message_bus.instrument("instantiation.active_record", payload) do - result_set.map { |record| instantiate(record, column_types, &block) } + if result_set.includes_column?(inheritance_column) + result_set.map { |record| instantiate(record, column_types, &block) } + else + # Instantiate a homogeneous set + result_set.map { |record| instantiate_instance_of(self, record, column_types, &block) } + end end end diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake index 24449e8df3..8b7d18fb3d 100644 --- a/activerecord/lib/active_record/railties/databases.rake +++ b/activerecord/lib/active_record/railties/databases.rake @@ -217,7 +217,7 @@ db_namespace = namespace :db do task setup: ["db:schema:load_if_ruby", "db:structure:load_if_sql", :seed] desc "Loads the seed data from db/seeds.rb" - task :seed do + task seed: :load_config do db_namespace["abort_if_pending_migrations"].invoke ActiveRecord::Tasks::DatabaseTasks.load_seed end diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index 22d195c9a4..6d2f75a3ae 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -13,33 +13,37 @@ module ActiveRecord class_attribute :aggregate_reflections, instance_writer: false, default: {} end - def self.create(macro, name, scope, options, ar) - klass = \ - case macro - when :composed_of - AggregateReflection - when :has_many - HasManyReflection - when :has_one - HasOneReflection - when :belongs_to - BelongsToReflection - else - raise "Unsupported Macro: #{macro}" - end + class << self + def create(macro, name, scope, options, ar) + reflection = reflection_class_for(macro).new(name, scope, options, ar) + options[:through] ? ThroughReflection.new(reflection) : reflection + end - reflection = klass.new(name, scope, options, ar) - options[:through] ? ThroughReflection.new(reflection) : reflection - end + def add_reflection(ar, name, reflection) + ar.clear_reflections_cache + name = name.to_s + ar._reflections = ar._reflections.except(name).merge!(name => reflection) + end - def self.add_reflection(ar, name, reflection) - ar.clear_reflections_cache - name = name.to_s - ar._reflections = ar._reflections.except(name).merge!(name => reflection) - end + def add_aggregate_reflection(ar, name, reflection) + ar.aggregate_reflections = ar.aggregate_reflections.merge(name.to_s => reflection) + end - def self.add_aggregate_reflection(ar, name, reflection) - ar.aggregate_reflections = ar.aggregate_reflections.merge(name.to_s => reflection) + private + def reflection_class_for(macro) + case macro + when :composed_of + AggregateReflection + when :has_many + HasManyReflection + when :has_one + HasOneReflection + when :belongs_to + BelongsToReflection + else + raise "Unsupported Macro: #{macro}" + end + end end # \Reflection enables the ability to examine the associations and aggregations of diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index c055b97061..fce5b66719 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -309,10 +309,10 @@ module ActiveRecord # Please check unscoped if you want to remove all previous scopes (including # the default_scope) during the execution of a block. def scoping - previous, klass.current_scope = klass.current_scope(true), self + previous, klass.current_scope = klass.current_scope(true), self unless @delegate_to_klass yield ensure - klass.current_scope = previous + klass.current_scope = previous unless @delegate_to_klass end def _exec_scope(*args, &block) # :nodoc: @@ -393,10 +393,7 @@ module ActiveRecord # Person.where(name: 'David').touch_all # # => "UPDATE \"people\" SET \"updated_at\" = '2018-01-04 22:55:23.132670' WHERE \"people\".\"name\" = 'David'" def touch_all(*names, time: nil) - attributes = Array(names) + klass.timestamp_attributes_for_update_in_model - time ||= klass.current_time_from_proper_timezone - updates = {} - attributes.each { |column| updates[column] = time } + updates = touch_attributes_with_time(*names, time: time) if klass.locking_enabled? quoted_locking_column = connection.quote_column_name(klass.locking_column) @@ -505,17 +502,16 @@ module ActiveRecord # # => SELECT "users".* FROM "users" WHERE "users"."name" = 'Oscar' def to_sql @to_sql ||= begin - relation = self - - if eager_loading? - apply_join_dependency { |rel, _| relation = rel } - end - - conn = klass.connection - conn.unprepared_statement { - conn.to_sql(relation.arel) - } - end + if eager_loading? + apply_join_dependency do |relation, join_dependency| + relation = join_dependency.apply_column_aliases(relation) + relation.to_sql + end + else + conn = klass.connection + conn.unprepared_statement { conn.to_sql(arel) } + end + end end # Returns a hash of where conditions. @@ -625,6 +621,7 @@ module ActiveRecord if ActiveRecord::NullRelation === relation [] else + relation = join_dependency.apply_column_aliases(relation) rows = connection.select_all(relation.arel, "SQL") join_dependency.instantiate(rows, &block) end.freeze diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb index f7613a187d..93f3b67686 100644 --- a/activerecord/lib/active_record/relation/finder_methods.rb +++ b/activerecord/lib/active_record/relation/finder_methods.rb @@ -371,16 +371,14 @@ module ActiveRecord relation end - def construct_join_dependency - including = eager_load_values + includes_values - joins = joins_values.select { |join| join.is_a?(Arel::Nodes::Join) } + def construct_join_dependency(associations) ActiveRecord::Associations::JoinDependency.new( - klass, table, including, alias_tracker(joins) + klass, table, associations ) end - def apply_join_dependency(eager_loading: true) - join_dependency = construct_join_dependency + def apply_join_dependency(eager_loading: group_values.empty?) + join_dependency = construct_join_dependency(eager_load_values + includes_values) relation = except(:includes, :eager_load, :preload).joins!(join_dependency) if eager_loading && !using_limitable_reflections?(join_dependency.reflections) @@ -392,7 +390,6 @@ module ActiveRecord end if block_given? - relation._select!(join_dependency.aliases.columns) yield relation, join_dependency else relation @@ -553,7 +550,7 @@ module ActiveRecord end def ordered_relation - if order_values.empty? && primary_key + if order_values.empty? && primary_key && limit_value.blank? order(arel_attribute(primary_key).asc) else self diff --git a/activerecord/lib/active_record/relation/merger.rb b/activerecord/lib/active_record/relation/merger.rb index 25510d4a57..10e4779ca4 100644 --- a/activerecord/lib/active_record/relation/merger.rb +++ b/activerecord/lib/active_record/relation/merger.rb @@ -117,14 +117,10 @@ module ActiveRecord if other.klass == relation.klass relation.joins!(*other.joins_values) else - alias_tracker = nil joins_dependency = other.joins_values.map do |join| case join when Hash, Symbol, Array - alias_tracker ||= other.alias_tracker - ActiveRecord::Associations::JoinDependency.new( - other.klass, other.table, join, alias_tracker - ) + other.send(:construct_join_dependency, join) else join end @@ -140,14 +136,10 @@ module ActiveRecord if other.klass == relation.klass relation.left_outer_joins!(*other.left_outer_joins_values) else - alias_tracker = nil joins_dependency = other.left_outer_joins_values.map do |join| case join when Hash, Symbol, Array - alias_tracker ||= other.alias_tracker - ActiveRecord::Associations::JoinDependency.new( - other.klass, other.table, join, alias_tracker - ) + other.send(:construct_join_dependency, join) else join end diff --git a/activerecord/lib/active_record/relation/predicate_builder.rb b/activerecord/lib/active_record/relation/predicate_builder.rb index 7a0edcbc33..f734cd0ad8 100644 --- a/activerecord/lib/active_record/relation/predicate_builder.rb +++ b/activerecord/lib/active_record/relation/predicate_builder.rb @@ -48,7 +48,12 @@ module ActiveRecord end def build(attribute, value) - handler_for(value).call(attribute, value) + if table.type(attribute.name).force_equality?(value) + bind = build_bind_attribute(attribute.name, value) + attribute.eq(bind) + else + handler_for(value).call(attribute, value) + end end def build_bind_attribute(column_name, value) @@ -95,10 +100,6 @@ module ActiveRecord end.reduce(&:and) end queries.reduce(&:or) - # FIXME: Deprecate this and provide a public API to force equality - elsif (value.is_a?(Range) || value.is_a?(Array)) && - table.type(key.to_s).respond_to?(:subtype) - BasicObjectHandler.new(self).call(table.arel_attribute(key), value) else build(table.arel_attribute(key), value) end diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index db9101a168..52405f21a1 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -1018,19 +1018,17 @@ module ActiveRecord def build_join_query(manager, buckets, join_type, aliases) buckets.default = [] - association_joins = buckets[:association_join] - stashed_association_joins = buckets[:stashed_join] - join_nodes = buckets[:join_node].uniq - string_joins = buckets[:string_join].map(&:strip).uniq + association_joins = buckets[:association_join] + stashed_joins = buckets[:stashed_join] + join_nodes = buckets[:join_node].uniq + string_joins = buckets[:string_join].map(&:strip).uniq join_list = join_nodes + convert_join_strings_to_ast(string_joins) alias_tracker = alias_tracker(join_list, aliases) - join_dependency = ActiveRecord::Associations::JoinDependency.new( - klass, table, association_joins, alias_tracker - ) + join_dependency = construct_join_dependency(association_joins) - joins = join_dependency.join_constraints(stashed_association_joins, join_type) + joins = join_dependency.join_constraints(stashed_joins, join_type, alias_tracker) joins.each { |join| manager.from(join) } manager.join_sources.concat(join_list) @@ -1056,11 +1054,13 @@ module ActiveRecord end def arel_columns(columns) - columns.map do |field| + columns.flat_map do |field| if (Symbol === field || String === field) && (klass.has_attribute?(field) || klass.attribute_alias?(field)) && !from_clause.value arel_attribute(field) elsif Symbol === field connection.quote_table_name(field.to_s) + elsif Proc === field + field.call else field end diff --git a/activerecord/lib/active_record/relation/spawn_methods.rb b/activerecord/lib/active_record/relation/spawn_methods.rb index b092399657..562e04194c 100644 --- a/activerecord/lib/active_record/relation/spawn_methods.rb +++ b/activerecord/lib/active_record/relation/spawn_methods.rb @@ -10,7 +10,6 @@ module ActiveRecord def spawn #:nodoc: clone end - alias :all :spawn # Merges in the conditions from <tt>other</tt>, if <tt>other</tt> is an ActiveRecord::Relation. # Returns an array representing the intersection of the resulting records with <tt>other</tt>, if <tt>other</tt> is an array. diff --git a/activerecord/lib/active_record/result.rb b/activerecord/lib/active_record/result.rb index e54e8086dd..7f1c2fd7eb 100644 --- a/activerecord/lib/active_record/result.rb +++ b/activerecord/lib/active_record/result.rb @@ -43,6 +43,11 @@ module ActiveRecord @column_types = column_types end + # Returns true if this result set includes the column named +name+ + def includes_column?(name) + @columns.include? name + end + # Returns the number of elements in the rows array. def length @rows.length @@ -97,12 +102,21 @@ module ActiveRecord end def cast_values(type_overrides = {}) # :nodoc: - types = columns.map { |name| column_type(name, type_overrides) } - result = rows.map do |values| - types.zip(values).map { |type, value| type.deserialize(value) } - end + if columns.one? + # Separated to avoid allocating an array per row - columns.one? ? result.map!(&:first) : result + type = column_type(columns.first, type_overrides) + + rows.map do |(value)| + type.deserialize(value) + end + else + types = columns.map { |name| column_type(name, type_overrides) } + + rows.map do |values| + Array.new(values.size) { |i| types[i].deserialize(values[i]) } + end + end end def initialize_copy(other) @@ -125,7 +139,7 @@ module ActiveRecord begin # We freeze the strings to prevent them getting duped when # used as keys in ActiveRecord::Base's @attributes hash - columns = @columns.map { |c| c.dup.freeze } + columns = @columns.map(&:-@) @rows.map { |row| # In the past we used Hash[columns.zip(row)] # though elegant, the verbose way is much more efficient diff --git a/activerecord/lib/active_record/store.rb b/activerecord/lib/active_record/store.rb index 8d628359c3..3537e2d008 100644 --- a/activerecord/lib/active_record/store.rb +++ b/activerecord/lib/active_record/store.rb @@ -33,12 +33,16 @@ module ActiveRecord # store :settings, accessors: [ :color, :homepage ], coder: JSON # store :parent, accessors: [ :name ], coder: JSON, prefix: true # store :spouse, accessors: [ :name ], coder: JSON, prefix: :partner + # store :settings, accessors: [ :two_factor_auth ], suffix: true + # store :settings, accessors: [ :login_retry ], suffix: :config # end # # u = User.new(color: 'black', homepage: '37signals.com', parent_name: 'Mary', partner_name: 'Lily') # u.color # Accessor stored attribute # u.parent_name # Accessor stored attribute with prefix # u.partner_name # Accessor stored attribute with custom prefix + # u.two_factor_auth_settings # Accessor stored attribute with suffix + # u.login_retry_config # Accessor stored attribute with custom suffix # u.settings[:country] = 'Denmark' # Any attribute, even if not specified with an accessor # # # There is no difference between strings and symbols for accessing custom attributes @@ -49,11 +53,12 @@ module ActiveRecord # class SuperUser < User # store_accessor :settings, :privileges, :servants # store_accessor :parent, :birthday, prefix: true + # store_accessor :settings, :secret_question, suffix: :config # end # # The stored attribute names can be retrieved using {.stored_attributes}[rdoc-ref:rdoc-ref:ClassMethods#stored_attributes]. # - # User.stored_attributes[:settings] # [:color, :homepage] + # User.stored_attributes[:settings] # [:color, :homepage, :two_factor_auth, :login_retry] # # == Overwriting default accessors # @@ -86,10 +91,10 @@ module ActiveRecord module ClassMethods def store(store_attribute, options = {}) serialize store_attribute, IndifferentCoder.new(store_attribute, options[:coder]) - store_accessor(store_attribute, options[:accessors], prefix: options[:prefix]) if options.has_key? :accessors + store_accessor(store_attribute, options[:accessors], options.slice(:prefix, :suffix)) if options.has_key? :accessors end - def store_accessor(store_attribute, *keys, prefix: nil) + def store_accessor(store_attribute, *keys, prefix: nil, suffix: nil) keys = keys.flatten accessor_prefix = @@ -101,14 +106,25 @@ module ActiveRecord else "" end + accessor_suffix = + case suffix + when String, Symbol + "_#{suffix}" + when TrueClass + "_#{store_attribute}" + else + "" + end _store_accessors_module.module_eval do keys.each do |key| - define_method("#{accessor_prefix}#{key}=") do |value| + accessor_key = "#{accessor_prefix}#{key}#{accessor_suffix}" + + define_method("#{accessor_key}=") do |value| write_store_attribute(store_attribute, key, value) end - define_method("#{accessor_prefix}#{key}") do + define_method(accessor_key) do read_store_attribute(store_attribute, key) end end diff --git a/activerecord/lib/active_record/timestamp.rb b/activerecord/lib/active_record/timestamp.rb index e47f06bf3a..d32f971ad1 100644 --- a/activerecord/lib/active_record/timestamp.rb +++ b/activerecord/lib/active_record/timestamp.rb @@ -53,12 +53,10 @@ module ActiveRecord end module ClassMethods # :nodoc: - def timestamp_attributes_for_update_in_model - timestamp_attributes_for_update.select { |c| column_names.include?(c) } - end - - def current_time_from_proper_timezone - default_timezone == :utc ? Time.now.utc : Time.now + def touch_attributes_with_time(*names, time: nil) + attribute_names = timestamp_attributes_for_update_in_model + attribute_names |= names.map(&:to_s) + attribute_names.index_with(time ||= current_time_from_proper_timezone) end private @@ -66,6 +64,10 @@ module ActiveRecord timestamp_attributes_for_create.select { |c| column_names.include?(c) } end + def timestamp_attributes_for_update_in_model + timestamp_attributes_for_update.select { |c| column_names.include?(c) } + end + def all_timestamp_attributes_in_model timestamp_attributes_for_create_in_model + timestamp_attributes_for_update_in_model end @@ -77,6 +79,10 @@ module ActiveRecord def timestamp_attributes_for_update ["updated_at", "updated_on"] end + + def current_time_from_proper_timezone + default_timezone == :utc ? Time.now.utc : Time.now + end end private @@ -116,7 +122,7 @@ module ActiveRecord end def timestamp_attributes_for_update_in_model - self.class.timestamp_attributes_for_update_in_model + self.class.send(:timestamp_attributes_for_update_in_model) end def all_timestamp_attributes_in_model @@ -124,7 +130,7 @@ module ActiveRecord end def current_time_from_proper_timezone - self.class.current_time_from_proper_timezone + self.class.send(:current_time_from_proper_timezone) end def max_updated_column_timestamp(timestamp_names = timestamp_attributes_for_update_in_model) diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb index 82adb19f5b..c5d5fca672 100644 --- a/activerecord/lib/active_record/transactions.rb +++ b/activerecord/lib/active_record/transactions.rb @@ -328,10 +328,12 @@ module ActiveRecord # but call it after the commit of a destroyed object. def committed!(should_run_callbacks: true) #:nodoc: if should_run_callbacks && (destroyed? || persisted?) + @_committed_already_called = true _run_commit_without_transaction_enrollment_callbacks _run_commit_callbacks end ensure + @_committed_already_called = false force_clear_transaction_record_state end @@ -380,6 +382,7 @@ module ActiveRecord end private + attr_reader :_committed_already_called, :_trigger_update_callback, :_trigger_destroy_callback # Save the new record state and id of a record so it can be restored later if a transaction fails. def remember_transaction_record_state @@ -390,6 +393,15 @@ module ActiveRecord frozen?: frozen?, ) @_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) + 1 + remember_new_record_before_last_commit + end + + def remember_new_record_before_last_commit + if _committed_already_called + @_new_record_before_last_commit = false + else + @_new_record_before_last_commit = @_start_transaction_state[:new_record] + end end # Clear the new record state and id of a record. @@ -421,22 +433,16 @@ module ActiveRecord end end - # Determine if a record was created or destroyed in a transaction. State should be one of :new_record or :destroyed. - def transaction_record_state(state) - @_start_transaction_state[state] - end - # Determine if a transaction included an action for :create, :update, or :destroy. Used in filtering callbacks. def transaction_include_any_action?(actions) actions.any? do |action| case action when :create - transaction_record_state(:new_record) - when :destroy - defined?(@_trigger_destroy_callback) && @_trigger_destroy_callback + persisted? && @_new_record_before_last_commit when :update - !(transaction_record_state(:new_record) || destroyed?) && - (defined?(@_trigger_update_callback) && @_trigger_update_callback) + !(@_new_record_before_last_commit || destroyed?) && _trigger_update_callback + when :destroy + _trigger_destroy_callback end end end diff --git a/activerecord/lib/active_record/type/serialized.rb b/activerecord/lib/active_record/type/serialized.rb index e882784691..0a2f6cb9fb 100644 --- a/activerecord/lib/active_record/type/serialized.rb +++ b/activerecord/lib/active_record/type/serialized.rb @@ -51,6 +51,10 @@ module ActiveRecord end end + def force_equality?(value) + coder.respond_to?(:object_class) && value.is_a?(coder.object_class) + end + private def default_value?(value) diff --git a/activerecord/lib/arel/visitors/postgresql.rb b/activerecord/lib/arel/visitors/postgresql.rb index 108ee431ee..c5110fa89c 100644 --- a/activerecord/lib/arel/visitors/postgresql.rb +++ b/activerecord/lib/arel/visitors/postgresql.rb @@ -5,7 +5,7 @@ module Arel # :nodoc: all class PostgreSQL < Arel::Visitors::ToSql CUBE = "CUBE" ROLLUP = "ROLLUP" - GROUPING_SET = "GROUPING SET" + GROUPING_SETS = "GROUPING SETS" LATERAL = "LATERAL" private @@ -67,7 +67,7 @@ module Arel # :nodoc: all end def visit_Arel_Nodes_GroupingSet(o, collector) - collector << GROUPING_SET + collector << GROUPING_SETS grouping_array_or_grouping_element o, collector end diff --git a/activerecord/test/cases/adapters/mysql2/active_schema_test.rb b/activerecord/test/cases/adapters/mysql2/active_schema_test.rb index 976c5dde58..58fa39d18c 100644 --- a/activerecord/test/cases/adapters/mysql2/active_schema_test.rb +++ b/activerecord/test/cases/adapters/mysql2/active_schema_test.rb @@ -158,7 +158,6 @@ class Mysql2ActiveSchemaTest < ActiveRecord::Mysql2TestCase def test_indexes_in_create ActiveRecord::Base.connection.stubs(:data_source_exists?).with(:temp).returns(false) - ActiveRecord::Base.connection.stubs(:index_name_exists?).with(:index_temp_on_zip).returns(false) expected = "CREATE TEMPORARY TABLE `temp` ( INDEX `index_temp_on_zip` (`zip`)) AS SELECT id, name, zip FROM a_really_complicated_query" actual = ActiveRecord::Base.connection.create_table(:temp, temporary: true, as: "SELECT id, name, zip FROM a_really_complicated_query") do |t| diff --git a/activerecord/test/cases/adapters/mysql2/datetime_precision_quoting_test.rb b/activerecord/test/cases/adapters/mysql2/datetime_precision_quoting_test.rb index fa54f39992..00a075e063 100644 --- a/activerecord/test/cases/adapters/mysql2/datetime_precision_quoting_test.rb +++ b/activerecord/test/cases/adapters/mysql2/datetime_precision_quoting_test.rb @@ -45,9 +45,10 @@ class Mysql2DatetimePrecisionQuotingTest < ActiveRecord::Mysql2TestCase end def stub_version(full_version_string) - @connection.stubs(:full_version).returns(full_version_string) - @connection.remove_instance_variable(:@version) if @connection.instance_variable_defined?(:@version) - yield + @connection.stub(:full_version, full_version_string) do + @connection.remove_instance_variable(:@version) if @connection.instance_variable_defined?(:@version) + yield + end ensure @connection.remove_instance_variable(:@version) if @connection.instance_variable_defined?(:@version) end diff --git a/activerecord/test/cases/adapters/mysql2/virtual_column_test.rb b/activerecord/test/cases/adapters/mysql2/virtual_column_test.rb index ffde8ed4d8..8494acee3b 100644 --- a/activerecord/test/cases/adapters/mysql2/virtual_column_test.rb +++ b/activerecord/test/cases/adapters/mysql2/virtual_column_test.rb @@ -18,6 +18,7 @@ if ActiveRecord::Base.connection.supports_virtual_columns? t.string :name t.virtual :upper_name, type: :string, as: "UPPER(`name`)" t.virtual :name_length, type: :integer, as: "LENGTH(`name`)", stored: true + t.virtual :name_octet_length, type: :integer, as: "OCTET_LENGTH(`name`)", stored: true end VirtualColumn.create(name: "Rails") end @@ -55,7 +56,8 @@ if ActiveRecord::Base.connection.supports_virtual_columns? def test_schema_dumping output = dump_table_schema("virtual_columns") assert_match(/t\.virtual\s+"upper_name",\s+type: :string,\s+as: "(?:UPPER|UCASE)\(`name`\)"$/i, output) - assert_match(/t\.virtual\s+"name_length",\s+type: :integer,\s+as: "LENGTH\(`name`\)",\s+stored: true$/i, output) + assert_match(/t\.virtual\s+"name_length",\s+type: :integer,\s+as: "(?:octet_length|length)\(`name`\)",\s+stored: true$/i, output) + assert_match(/t\.virtual\s+"name_octet_length",\s+type: :integer,\s+as: "(?:octet_length|length)\(`name`\)",\s+stored: true$/i, output) end end end diff --git a/activerecord/test/cases/adapters/postgresql/connection_test.rb b/activerecord/test/cases/adapters/postgresql/connection_test.rb index d1b3c434e1..54b0dde7dc 100644 --- a/activerecord/test/cases/adapters/postgresql/connection_test.rb +++ b/activerecord/test/cases/adapters/postgresql/connection_test.rb @@ -151,7 +151,7 @@ module ActiveRecord # When prompted, restart the PostgreSQL server with the # "-m fast" option or kill the individual connection assuming # you know the incantation to do that. - # To restart PostgreSQL 9.1 on OS X, installed via MacPorts, ... + # To restart PostgreSQL 9.1 on macOS, installed via MacPorts, ... # sudo su postgres -c "pg_ctl restart -D /opt/local/var/db/postgresql91/defaultdb/ -m fast" def test_reconnection_after_actual_disconnection_with_verify original_connection_pid = @connection.query("select pg_backend_pid()") diff --git a/activerecord/test/cases/adapters/postgresql/money_test.rb b/activerecord/test/cases/adapters/postgresql/money_test.rb index be3590e8dd..61e75e772d 100644 --- a/activerecord/test/cases/adapters/postgresql/money_test.rb +++ b/activerecord/test/cases/adapters/postgresql/money_test.rb @@ -6,7 +6,9 @@ require "support/schema_dumping_helper" class PostgresqlMoneyTest < ActiveRecord::PostgreSQLTestCase include SchemaDumpingHelper - class PostgresqlMoney < ActiveRecord::Base; end + class PostgresqlMoney < ActiveRecord::Base + validates :depth, numericality: true + end setup do @connection = ActiveRecord::Base.connection @@ -35,6 +37,7 @@ class PostgresqlMoneyTest < ActiveRecord::PostgreSQLTestCase def test_default assert_equal BigDecimal("150.55"), PostgresqlMoney.column_defaults["depth"] assert_equal BigDecimal("150.55"), PostgresqlMoney.new.depth + assert_equal "$150.55", PostgresqlMoney.new.depth_before_type_cast end def test_money_values diff --git a/activerecord/test/cases/adapters/postgresql/range_test.rb b/activerecord/test/cases/adapters/postgresql/range_test.rb index 261c24634e..433598500d 100644 --- a/activerecord/test/cases/adapters/postgresql/range_test.rb +++ b/activerecord/test/cases/adapters/postgresql/range_test.rb @@ -341,6 +341,12 @@ _SQL assert_equal record, PostgresqlRange.where(int4_range: range).take end + def test_where_by_attribute_with_range_in_array + range = 1..100 + record = PostgresqlRange.create!(int4_range: range) + assert_equal record, PostgresqlRange.where(int4_range: [range]).take + end + def test_update_all_with_ranges PostgresqlRange.create! diff --git a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb index ad155c7492..d1d4d545a3 100644 --- a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb +++ b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb @@ -504,6 +504,39 @@ module ActiveRecord assert_deprecated { @conn.valid_alter_table_type?(:string) } end + def test_db_is_not_readonly_when_readonly_option_is_false + conn = Base.sqlite3_connection database: ":memory:", + adapter: "sqlite3", + readonly: false + + assert_not_predicate conn.raw_connection, :readonly? + end + + def test_db_is_not_readonly_when_readonly_option_is_unspecified + conn = Base.sqlite3_connection database: ":memory:", + adapter: "sqlite3" + + assert_not_predicate conn.raw_connection, :readonly? + end + + def test_db_is_readonly_when_readonly_option_is_true + conn = Base.sqlite3_connection database: ":memory:", + adapter: "sqlite3", + readonly: true + + assert_predicate conn.raw_connection, :readonly? + end + + def test_writes_are_not_permitted_to_readonly_databases + conn = Base.sqlite3_connection database: ":memory:", + adapter: "sqlite3", + readonly: true + + assert_raises(ActiveRecord::StatementInvalid, /SQLite3::ReadOnlyException/) do + conn.execute("CREATE TABLE test(id integer)") + end + end + private def assert_logged(logs) diff --git a/activerecord/test/cases/arel/insert_manager_test.rb b/activerecord/test/cases/arel/insert_manager_test.rb index ae10ccf56c..2376ad8d37 100644 --- a/activerecord/test/cases/arel/insert_manager_test.rb +++ b/activerecord/test/cases/arel/insert_manager_test.rb @@ -220,7 +220,6 @@ module Arel end describe "select" do - it "accepts a select query in place of a VALUES clause" do table = Table.new :users @@ -238,7 +237,6 @@ module Arel INSERT INTO "users" ("id", "name") (SELECT 1, "aaron") } end - end end end diff --git a/activerecord/test/cases/arel/select_manager_test.rb b/activerecord/test/cases/arel/select_manager_test.rb index f318577b94..6b10d0b612 100644 --- a/activerecord/test/cases/arel/select_manager_test.rb +++ b/activerecord/test/cases/arel/select_manager_test.rb @@ -244,8 +244,6 @@ module Arel @m2 = Arel::SelectManager.new table @m2.project Arel.star @m2.where(table[:age].gt(99)) - - end it "should union two managers" do @@ -266,7 +264,6 @@ module Arel ( SELECT * FROM "users" WHERE "users"."age" < 18 UNION ALL SELECT * FROM "users" WHERE "users"."age" > 99 ) } end - end describe "intersect" do @@ -279,8 +276,6 @@ module Arel @m2 = Arel::SelectManager.new table @m2.project Arel.star @m2.where(table[:age].lt(99)) - - end it "should interect two managers" do @@ -293,7 +288,6 @@ module Arel ( SELECT * FROM "users" WHERE "users"."age" > 18 INTERSECT SELECT * FROM "users" WHERE "users"."age" < 99 ) } end - end describe "except" do @@ -318,7 +312,6 @@ module Arel ( SELECT * FROM "users" WHERE "users"."age" BETWEEN 18 AND 60 EXCEPT SELECT * FROM "users" WHERE "users"."age" BETWEEN 40 AND 99 ) } end - end describe "with" do @@ -647,7 +640,6 @@ module Arel end describe "joins" do - it "returns inner join sql" do table = Table.new :users aliaz = table.alias @@ -1002,7 +994,6 @@ module Arel end describe "update" do - it "creates an update statement" do table = Table.new :users manager = Arel::SelectManager.new @@ -1075,7 +1066,6 @@ module Arel UPDATE "users" SET "id" = 1 WHERE "users"."id" IN (SELECT "users"."id" FROM "users" WHERE "users"."foo" = 10 LIMIT 42) } end - end describe "project" do @@ -1097,7 +1087,6 @@ module Arel manager.project "*" manager.to_sql.must_be_like %{ SELECT * } end - end describe "projections" do diff --git a/activerecord/test/cases/arel/visitors/postgres_test.rb b/activerecord/test/cases/arel/visitors/postgres_test.rb index ba37afecfb..ba9cfcfc64 100644 --- a/activerecord/test/cases/arel/visitors/postgres_test.rb +++ b/activerecord/test/cases/arel/visitors/postgres_test.rb @@ -229,7 +229,7 @@ module Arel it "should know how to visit with array arguments" do node = Arel::Nodes::GroupingSet.new([@table[:name], @table[:bool]]) compile(node).must_be_like %{ - GROUPING SET( "users"."name", "users"."bool" ) + GROUPING SETS( "users"."name", "users"."bool" ) } end @@ -237,7 +237,7 @@ module Arel group = Arel::Nodes::GroupingElement.new([@table[:name], @table[:bool]]) node = Arel::Nodes::GroupingSet.new(group) compile(node).must_be_like %{ - GROUPING SET( "users"."name", "users"."bool" ) + GROUPING SETS( "users"."name", "users"."bool" ) } end @@ -246,7 +246,7 @@ module Arel group2 = Arel::Nodes::GroupingElement.new([@table[:bool], @table[:created_at]]) node = Arel::Nodes::GroupingSet.new([group1, group2]) compile(node).must_be_like %{ - GROUPING SET( ( "users"."name" ), ( "users"."bool", "users"."created_at" ) ) + GROUPING SETS( ( "users"."name" ), ( "users"."bool", "users"."created_at" ) ) } end end diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb index 5011a9bbde..0cc4ed7127 100644 --- a/activerecord/test/cases/associations/belongs_to_associations_test.rb +++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb @@ -44,6 +44,14 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase assert_raise(frozen_error_class) { client.firm = Firm.new(name: "Firm") } end + def test_eager_loading_wont_mutate_owner_record + client = Client.eager_load(:firm_with_basic_id).first + assert_not_predicate client, :firm_id_came_from_user? + + client = Client.preload(:firm_with_basic_id).first + assert_not_predicate client, :firm_id_came_from_user? + end + def test_missing_attribute_error_is_raised_when_no_foreign_key_attribute assert_raises(ActiveModel::MissingAttributeError) { Client.select(:id).first.firm } end @@ -458,7 +466,20 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase def test_belongs_to_with_primary_key_counter debate = Topic.create("title" => "debate") debate2 = Topic.create("title" => "debate2") - reply = Reply.create("title" => "blah!", "content" => "world around!", "parent_title" => "debate") + reply = Reply.create("title" => "blah!", "content" => "world around!", "parent_title" => "debate2") + + assert_equal 0, debate.reload.replies_count + assert_equal 1, debate2.reload.replies_count + + reply.parent_title = "debate" + reply.save! + + assert_equal 1, debate.reload.replies_count + assert_equal 0, debate2.reload.replies_count + + assert_no_queries do + reply.topic_with_primary_key = debate + end assert_equal 1, debate.reload.replies_count assert_equal 0, debate2.reload.replies_count @@ -536,6 +557,48 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase assert_equal 1, Topic.find(topic.id)[:replies_count] end + def test_belongs_to_counter_after_touch + topic = Topic.create!(title: "topic") + + assert_equal 0, topic.replies_count + assert_equal 0, topic.after_touch_called + + reply = Reply.create!(title: "blah!", content: "world around!", topic_with_primary_key: topic) + + assert_equal 1, topic.replies_count + assert_equal 1, topic.after_touch_called + + reply.destroy! + + assert_equal 0, topic.replies_count + assert_equal 2, topic.after_touch_called + end + + def test_belongs_to_touch_with_reassigning + debate = Topic.create!(title: "debate") + debate2 = Topic.create!(title: "debate2") + reply = Reply.create!(title: "blah!", content: "world around!", parent_title: "debate2") + + time = 1.day.ago + + debate.touch(time: time) + debate2.touch(time: time) + + reply.parent_title = "debate" + reply.save! + + assert_operator debate.reload.updated_at, :>, time + assert_operator debate2.reload.updated_at, :>, time + + debate.touch(time: time) + debate2.touch(time: time) + + reply.topic_with_primary_key = debate2 + + assert_operator debate.reload.updated_at, :>, time + assert_operator debate2.reload.updated_at, :>, time + end + def test_belongs_to_with_touch_option_on_touch line_item = LineItem.create! Invoice.create!(line_items: [line_item]) @@ -1050,9 +1113,20 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase post = posts(:welcome) comment = comments(:greetings) - assert_difference lambda { post.reload.tags_count }, -1 do + assert_equal post.id, comment.id + + assert_difference "post.reload.tags_count", -1 do assert_difference "comment.reload.tags_count", +1 do tagging.taggable = comment + tagging.save! + end + end + + assert_difference "comment.reload.tags_count", -1 do + assert_difference "post.reload.tags_count", +1 do + tagging.taggable_type = post.class.polymorphic_name + tagging.taggable_id = post.id + tagging.save! end end end diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb index f46be8734b..5b8d4722af 100644 --- a/activerecord/test/cases/associations/eager_test.rb +++ b/activerecord/test/cases/associations/eager_test.rb @@ -77,8 +77,68 @@ class EagerAssociationTest < ActiveRecord::TestCase end def test_loading_with_scope_including_joins - assert_equal clubs(:boring_club), Member.preload(:general_club).find(1).general_club - assert_equal clubs(:boring_club), Member.eager_load(:general_club).find(1).general_club + member = Member.first + assert_equal members(:groucho), member + assert_equal clubs(:boring_club), member.general_club + + member = Member.preload(:general_club).first + assert_equal members(:groucho), member + assert_equal clubs(:boring_club), member.general_club + + member = Member.eager_load(:general_club).first + assert_equal members(:groucho), member + assert_equal clubs(:boring_club), member.general_club + end + + def test_loading_association_with_same_table_joins + super_memberships = [memberships(:super_membership_of_boring_club)] + + member = Member.joins(:favourite_memberships).first + assert_equal members(:groucho), member + assert_equal super_memberships, member.super_memberships + + member = Member.joins(:favourite_memberships).preload(:super_memberships).first + assert_equal members(:groucho), member + assert_equal super_memberships, member.super_memberships + + member = Member.joins(:favourite_memberships).eager_load(:super_memberships).first + assert_equal members(:groucho), member + assert_equal super_memberships, member.super_memberships + end + + def test_loading_association_with_intersection_joins + member = Member.joins(:current_membership).first + assert_equal members(:groucho), member + assert_equal clubs(:boring_club), member.club + assert_equal memberships(:membership_of_boring_club), member.current_membership + + member = Member.joins(:current_membership).preload(:club, :current_membership).first + assert_equal members(:groucho), member + assert_equal clubs(:boring_club), member.club + assert_equal memberships(:membership_of_boring_club), member.current_membership + + member = Member.joins(:current_membership).eager_load(:club, :current_membership).first + assert_equal members(:groucho), member + assert_equal clubs(:boring_club), member.club + assert_equal memberships(:membership_of_boring_club), member.current_membership + end + + def test_loading_associations_dont_leak_instance_state + assertions = ->(firm) { + assert_equal companies(:first_firm), firm + + assert_predicate firm.association(:readonly_account), :loaded? + assert_predicate firm.association(:accounts), :loaded? + + assert_equal accounts(:signals37), firm.readonly_account + assert_equal [accounts(:signals37)], firm.accounts + + assert_predicate firm.readonly_account, :readonly? + assert firm.accounts.none?(&:readonly?) + } + + assertions.call(Firm.preload(:readonly_account, :accounts).first) + assertions.call(Firm.eager_load(:readonly_account, :accounts).first) end def test_with_ordering diff --git a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb index 5d9735d98a..f414fbf64b 100644 --- a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb @@ -697,24 +697,13 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase end def test_join_table_alias - # FIXME: `references` has no impact on the aliases generated for the join - # query. The fact that we pass `:developers_projects_join` to `references` - # and that the SQL string contains `developers_projects_join` is merely a - # coincidence. assert_equal( 3, - Developer.references(:developers_projects_join).merge( - includes: { projects: :developers }, - where: "projects_developers_projects_join.joined_on IS NOT NULL" - ).to_a.size + Developer.includes(projects: :developers).where.not("projects_developers_projects_join.joined_on": nil).to_a.size ) end def test_join_with_group - # FIXME: `references` has no impact on the aliases generated for the join - # query. The fact that we pass `:developers_projects_join` to `references` - # and that the SQL string contains `developers_projects_join` is merely a - # coincidence. group = Developer.columns.inject([]) do |g, c| g << "developers.#{c.name}" g << "developers_projects_2.#{c.name}" @@ -723,10 +712,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase assert_equal( 3, - Developer.references(:developers_projects_join).merge( - includes: { projects: :developers }, where: "projects_developers_projects_join.joined_on IS NOT NULL", - group: group.join(",") - ).to_a.size + Developer.includes(projects: :developers).where.not("projects_developers_projects_join.joined_on": nil).group(group.join(",")).to_a.size ) end diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index cc8f33f142..0ca902385a 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -2705,6 +2705,17 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end end + def test_create_children_could_be_rolled_back_by_after_save + firm = Firm.create!(name: "A New Firm, Inc") + assert_no_difference "Client.count" do + client = firm.clients.create(name: "New Client") do |cli| + cli.rollback_on_save = true + assert_not cli.rollback_on_create_called + end + assert client.rollback_on_create_called + end + end + private def force_signal37_to_load_all_clients_of_firm diff --git a/activerecord/test/cases/associations/has_many_through_associations_test.rb b/activerecord/test/cases/associations/has_many_through_associations_test.rb index 0facc286da..d5573b6d02 100644 --- a/activerecord/test/cases/associations/has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb @@ -737,6 +737,18 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase [:added, :before, "Roger"], [:added, :after, "Roger"] ], log.last(4) + + post.people_with_callbacks.build { |person| person.first_name = "Ted" } + assert_equal [ + [:added, :before, "Ted"], + [:added, :after, "Ted"] + ], log.last(2) + + post.people_with_callbacks.create { |person| person.first_name = "Sam" } + assert_equal [ + [:added, :before, "Sam"], + [:added, :after, "Sam"] + ], log.last(2) end def test_dynamic_find_should_respect_association_include @@ -1277,6 +1289,10 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase assert_equal authors(:david), Author.joins(:comments_for_first_author).take end + def test_has_many_through_with_left_joined_same_table_with_through_table + assert_equal [comments(:eager_other_comment1)], authors(:mary).comments.left_joins(:post) + end + def test_has_many_through_with_unscope_should_affect_to_through_scope assert_equal [comments(:eager_other_comment1)], authors(:mary).unordered_comments end diff --git a/activerecord/test/cases/attribute_methods_test.rb b/activerecord/test/cases/attribute_methods_test.rb index 434d32846c..0bfd46a522 100644 --- a/activerecord/test/cases/attribute_methods_test.rb +++ b/activerecord/test/cases/attribute_methods_test.rb @@ -163,19 +163,6 @@ class AttributeMethodsTest < ActiveRecord::TestCase assert_equal "10", keyboard.read_attribute_before_type_cast(:key_number) end - # Syck calls respond_to? before actually calling initialize. - test "respond_to? with an allocated object" do - klass = Class.new(ActiveRecord::Base) do - self.table_name = "topics" - end - - topic = klass.allocate - assert_not_respond_to topic, "nothingness" - assert_not_respond_to topic, :nothingness - assert_respond_to topic, "title" - assert_respond_to topic, :title - end - # IRB inspects the return value of MyModel.allocate. test "allocated objects can be inspected" do topic = Topic.allocate diff --git a/activerecord/test/cases/autosave_association_test.rb b/activerecord/test/cases/autosave_association_test.rb index 7355f4cd62..ade1f4b44d 100644 --- a/activerecord/test/cases/autosave_association_test.rb +++ b/activerecord/test/cases/autosave_association_test.rb @@ -27,6 +27,7 @@ require "models/member_detail" require "models/organization" require "models/guitar" require "models/tuning_peg" +require "models/reply" class TestAutosaveAssociationsInGeneral < ActiveRecord::TestCase def test_autosave_validation @@ -557,6 +558,21 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociation < ActiveRecord::TestCa assert_equal no_of_clients + 1, Client.count end + def test_parent_should_not_get_saved_with_duplicate_children_records + assert_no_difference "Reply.count" do + assert_no_difference "SillyUniqueReply.count" do + reply = Reply.new + reply.silly_unique_replies.build([ + { content: "Best content" }, + { content: "Best content" } + ]) + + assert_not reply.save + assert_not_empty reply.errors + end + end + end + def test_invalid_build new_client = companies(:first_firm).clients_of_firm.build assert_not_predicate new_client, :persisted? diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index fcfab074a2..d216fe16fa 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -14,7 +14,6 @@ require "models/computer" require "models/project" require "models/default" require "models/auto_id" -require "models/boolean" require "models/column_name" require "models/subscriber" require "models/comment" @@ -716,48 +715,6 @@ class BasicsTest < ActiveRecord::TestCase assert_equal expected_attributes, category.attributes end - def test_boolean - b_nil = Boolean.create("value" => nil) - nil_id = b_nil.id - b_false = Boolean.create("value" => false) - false_id = b_false.id - b_true = Boolean.create("value" => true) - true_id = b_true.id - - b_nil = Boolean.find(nil_id) - assert_nil b_nil.value - b_false = Boolean.find(false_id) - assert_not_predicate b_false, :value? - b_true = Boolean.find(true_id) - assert_predicate b_true, :value? - end - - def test_boolean_without_questionmark - b_true = Boolean.create("value" => true) - true_id = b_true.id - - subclass = Class.new(Boolean).find true_id - superclass = Boolean.find true_id - - assert_equal superclass.read_attribute(:has_fun), subclass.read_attribute(:has_fun) - end - - def test_boolean_cast_from_string - b_blank = Boolean.create("value" => "") - blank_id = b_blank.id - b_false = Boolean.create("value" => "0") - false_id = b_false.id - b_true = Boolean.create("value" => "1") - true_id = b_true.id - - b_blank = Boolean.find(blank_id) - assert_nil b_blank.value - b_false = Boolean.find(false_id) - assert_not_predicate b_false, :value? - b_true = Boolean.find(true_id) - assert_predicate b_true, :value? - end - def test_new_record_returns_boolean assert_equal false, Topic.new.persisted? assert_equal true, Topic.find(1).persisted? diff --git a/activerecord/test/cases/boolean_test.rb b/activerecord/test/cases/boolean_test.rb new file mode 100644 index 0000000000..ab9f974e2c --- /dev/null +++ b/activerecord/test/cases/boolean_test.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +require "cases/helper" +require "models/boolean" + +class BooleanTest < ActiveRecord::TestCase + def test_boolean + b_nil = Boolean.create!(value: nil) + b_false = Boolean.create!(value: false) + b_true = Boolean.create!(value: true) + + assert_nil Boolean.find(b_nil.id).value + assert_not_predicate Boolean.find(b_false.id), :value? + assert_predicate Boolean.find(b_true.id), :value? + end + + def test_boolean_without_questionmark + b_true = Boolean.create!(value: true) + + subclass = Class.new(Boolean).find(b_true.id) + superclass = Boolean.find(b_true.id) + + assert_equal superclass.read_attribute(:has_fun), subclass.read_attribute(:has_fun) + end + + def test_boolean_cast_from_string + b_blank = Boolean.create!(value: "") + b_false = Boolean.create!(value: "0") + b_true = Boolean.create!(value: "1") + + assert_nil Boolean.find(b_blank.id).value + assert_not_predicate Boolean.find(b_false.id), :value? + assert_predicate Boolean.find(b_true.id), :value? + end + + def test_find_by_boolean_string + b_false = Boolean.create!(value: "false") + b_true = Boolean.create!(value: "true") + + assert_equal b_false, Boolean.find_by(value: "false") + assert_equal b_true, Boolean.find_by(value: "true") + end +end diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb index 080d2a54bc..5c9ed42173 100644 --- a/activerecord/test/cases/calculations_test.rb +++ b/activerecord/test/cases/calculations_test.rb @@ -642,6 +642,18 @@ class CalculationsTest < ActiveRecord::TestCase assert_equal [ topic.written_on ], relation.pluck(:written_on) end + def test_pluck_with_type_cast_does_not_corrupt_the_query_cache + topic = topics(:first) + relation = Topic.where(id: topic.id) + assert_queries 1 do + Topic.cache do + kind = relation.select(:written_on).load.first.read_attribute_before_type_cast(:written_on).class + relation.pluck(:written_on) + assert_kind_of kind, relation.select(:written_on).load.first.read_attribute_before_type_cast(:written_on) + end + end + end + def test_pluck_and_distinct assert_equal [50, 53, 55, 60], Account.order(:credit_limit).distinct.pluck(:credit_limit) end @@ -705,6 +717,24 @@ class CalculationsTest < ActiveRecord::TestCase assert_equal [], Topic.includes(:replies).order(:id).offset(5).pluck(:id) end + def test_group_by_with_limit + expected = { "Post" => 8, "SpecialPost" => 1 } + actual = Post.includes(:comments).group(:type).order(:type).limit(2).count("comments.id") + assert_equal expected, actual + end + + def test_group_by_with_offset + expected = { "SpecialPost" => 1, "StiPost" => 2 } + actual = Post.includes(:comments).group(:type).order(:type).offset(1).count("comments.id") + assert_equal expected, actual + end + + def test_group_by_with_limit_and_offset + expected = { "SpecialPost" => 1 } + actual = Post.includes(:comments).group(:type).order(:type).offset(1).limit(1).count("comments.id") + assert_equal expected, actual + end + def test_pluck_not_auto_table_name_prefix_if_column_included Company.create!(name: "test", contracts: [Contract.new(developer_id: 7)]) ids = Company.includes(:contracts).pluck(:developer_id) diff --git a/activerecord/test/cases/counter_cache_test.rb b/activerecord/test/cases/counter_cache_test.rb index e0948f90ac..99d286dc52 100644 --- a/activerecord/test/cases/counter_cache_test.rb +++ b/activerecord/test/cases/counter_cache_test.rb @@ -280,38 +280,38 @@ class CounterCacheTest < ActiveRecord::TestCase end test "update counters with touch: :written_on" do - assert_touching @topic, :written_on do + assert_touching @topic, :updated_at, :written_on do Topic.update_counters(@topic.id, replies_count: -1, touch: :written_on) end end test "update multiple counters with touch: :written_on" do - assert_touching @topic, :written_on do + assert_touching @topic, :updated_at, :written_on do Topic.update_counters(@topic.id, replies_count: 2, unique_replies_count: 2, touch: :written_on) end end test "reset counters with touch: :written_on" do - assert_touching @topic, :written_on do + assert_touching @topic, :updated_at, :written_on do Topic.reset_counters(@topic.id, :replies, touch: :written_on) end end test "reset multiple counters with touch: :written_on" do - assert_touching @topic, :written_on do + assert_touching @topic, :updated_at, :written_on do Topic.update_counters(@topic.id, replies_count: 1, unique_replies_count: 1) Topic.reset_counters(@topic.id, :replies, :unique_replies, touch: :written_on) end end test "increment counters with touch: :written_on" do - assert_touching @topic, :written_on do + assert_touching @topic, :updated_at, :written_on do Topic.increment_counter(:replies_count, @topic.id, touch: :written_on) end end test "decrement counters with touch: :written_on" do - assert_touching @topic, :written_on do + assert_touching @topic, :updated_at, :written_on do Topic.decrement_counter(:replies_count, @topic.id, touch: :written_on) end end diff --git a/activerecord/test/cases/defaults_test.rb b/activerecord/test/cases/defaults_test.rb index 1c96aaabe2..0f957d41cf 100644 --- a/activerecord/test/cases/defaults_test.rb +++ b/activerecord/test/cases/defaults_test.rb @@ -106,21 +106,31 @@ if current_adapter?(:Mysql2Adapter) class MysqlDefaultExpressionTest < ActiveRecord::TestCase include SchemaDumpingHelper - if ActiveRecord::Base.connection.version >= "5.6.0" + if subsecond_precision_supported? test "schema dump datetime includes default expression" do output = dump_table_schema("datetime_defaults") - assert_match %r/t\.datetime\s+"modified_datetime",\s+default: -> { "CURRENT_TIMESTAMP" }/, output + assert_match %r/t\.datetime\s+"modified_datetime",\s+default: -> { "CURRENT_TIMESTAMP(?:\(\))?" }/i, output end - end - test "schema dump timestamp includes default expression" do - output = dump_table_schema("timestamp_defaults") - assert_match %r/t\.timestamp\s+"modified_timestamp",\s+default: -> { "CURRENT_TIMESTAMP" }/, output - end + test "schema dump datetime includes precise default expression" do + output = dump_table_schema("datetime_defaults") + assert_match %r/t\.datetime\s+"precise_datetime",.+default: -> { "CURRENT_TIMESTAMP\(6\)" }/i, output + end - test "schema dump timestamp without default expression" do - output = dump_table_schema("timestamp_defaults") - assert_match %r/t\.timestamp\s+"nullable_timestamp"$/, output + test "schema dump timestamp includes default expression" do + output = dump_table_schema("timestamp_defaults") + assert_match %r/t\.timestamp\s+"modified_timestamp",\s+default: -> { "CURRENT_TIMESTAMP(?:\(\))?" }/i, output + end + + test "schema dump timestamp includes precise default expression" do + output = dump_table_schema("timestamp_defaults") + assert_match %r/t\.timestamp\s+"precise_timestamp",.+default: -> { "CURRENT_TIMESTAMP\(6\)" }/i, output + end + + test "schema dump timestamp without default expression" do + output = dump_table_schema("timestamp_defaults") + assert_match %r/t\.timestamp\s+"nullable_timestamp"$/, output + end end end diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb index 8324b26ad3..2f256dd36a 100644 --- a/activerecord/test/cases/finder_test.rb +++ b/activerecord/test/cases/finder_test.rb @@ -355,6 +355,12 @@ class FinderTest < ActiveRecord::TestCase end def test_find_on_relation_with_large_number + assert_raises(ActiveRecord::RecordNotFound) do + Topic.where("1=1").find(9999999999999999999999999999999) + end + end + + def test_find_by_on_relation_with_large_number assert_nil Topic.where("1=1").find_by(id: 9999999999999999999999999999999) end @@ -1259,6 +1265,21 @@ class FinderTest < ActiveRecord::TestCase end end + def test_first_and_last_with_limit_for_order_without_primary_key + # While Topic.first should impose an ordering by primary key, + # Topic.limit(n).first should not + + Topic.first.touch # PostgreSQL changes the default order if no order clause is used + + assert_equal Topic.limit(1).to_a.first, Topic.limit(1).first + assert_equal Topic.limit(2).to_a.first, Topic.limit(2).first + assert_equal Topic.limit(2).to_a.first(2), Topic.limit(2).first(2) + + assert_equal Topic.limit(1).to_a.last, Topic.limit(1).last + assert_equal Topic.limit(2).to_a.last, Topic.limit(2).last + assert_equal Topic.limit(2).to_a.last(2), Topic.limit(2).last(2) + end + def test_finder_with_offset_string assert_nothing_raised { Topic.offset("3").to_a } end diff --git a/activerecord/test/cases/fixtures_test.rb b/activerecord/test/cases/fixtures_test.rb index ee88bd8144..c65523d8c1 100644 --- a/activerecord/test/cases/fixtures_test.rb +++ b/activerecord/test/cases/fixtures_test.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require "cases/helper" +require "support/connection_helper" require "models/admin" require "models/admin/account" require "models/admin/randomly_named_c1" @@ -32,6 +33,8 @@ require "models/treasure" require "tempfile" class FixturesTest < ActiveRecord::TestCase + include ConnectionHelper + self.use_instantiated_fixtures = true self.use_transactional_tests = false @@ -114,9 +117,96 @@ class FixturesTest < ActiveRecord::TestCase end end end + + def test_bulk_insert_with_a_multi_statement_query_in_a_nested_transaction + fixtures = { + "traffic_lights" => [ + { "location" => "US", "state" => ["NY"], "long_state" => ["a"] }, + ] + } + + assert_difference "TrafficLight.count" do + ActiveRecord::Base.transaction do + conn = ActiveRecord::Base.connection + assert_equal 1, conn.open_transactions + conn.insert_fixtures_set(fixtures) + assert_equal 1, conn.open_transactions + end + end + end end if current_adapter?(:Mysql2Adapter) + def test_bulk_insert_with_multi_statements_enabled + run_without_connection do |orig_connection| + ActiveRecord::Base.establish_connection( + orig_connection.merge(flags: %w[MULTI_STATEMENTS]) + ) + + fixtures = { + "traffic_lights" => [ + { "location" => "US", "state" => ["NY"], "long_state" => ["a"] }, + ] + } + + ActiveRecord::Base.connection.stub(:supports_set_server_option?, false) do + assert_nothing_raised do + conn = ActiveRecord::Base.connection + conn.execute("SELECT 1; SELECT 2;") + conn.raw_connection.abandon_results! + end + + assert_difference "TrafficLight.count" do + ActiveRecord::Base.transaction do + conn = ActiveRecord::Base.connection + assert_equal 1, conn.open_transactions + conn.insert_fixtures_set(fixtures) + assert_equal 1, conn.open_transactions + end + end + + assert_nothing_raised do + conn = ActiveRecord::Base.connection + conn.execute("SELECT 1; SELECT 2;") + conn.raw_connection.abandon_results! + end + end + end + end + + def test_bulk_insert_with_multi_statements_disabled + run_without_connection do |orig_connection| + ActiveRecord::Base.establish_connection( + orig_connection.merge(flags: []) + ) + + fixtures = { + "traffic_lights" => [ + { "location" => "US", "state" => ["NY"], "long_state" => ["a"] }, + ] + } + + ActiveRecord::Base.connection.stub(:supports_set_server_option?, false) do + assert_raises(ActiveRecord::StatementInvalid) do + conn = ActiveRecord::Base.connection + conn.execute("SELECT 1; SELECT 2;") + conn.raw_connection.abandon_results! + end + + assert_difference "TrafficLight.count" do + conn = ActiveRecord::Base.connection + conn.insert_fixtures_set(fixtures) + end + + assert_raises(ActiveRecord::StatementInvalid) do + conn = ActiveRecord::Base.connection + conn.execute("SELECT 1; SELECT 2;") + conn.raw_connection.abandon_results! + end + end + end + end + def test_insert_fixtures_set_raises_an_error_when_max_allowed_packet_is_smaller_than_fixtures_set_size conn = ActiveRecord::Base.connection mysql_margin = 2 @@ -128,10 +218,10 @@ class FixturesTest < ActiveRecord::TestCase ] } - conn.stubs(:max_allowed_packet).returns(packet_size - mysql_margin) - - error = assert_raises(ActiveRecord::ActiveRecordError) { conn.insert_fixtures_set(fixtures) } - assert_match(/Fixtures set is too large #{packet_size}\./, error.message) + conn.stub(:max_allowed_packet, packet_size - mysql_margin) do + error = assert_raises(ActiveRecord::ActiveRecordError) { conn.insert_fixtures_set(fixtures) } + assert_match(/Fixtures set is too large #{packet_size}\./, error.message) + end end def test_insert_fixture_set_when_max_allowed_packet_is_bigger_than_fixtures_set_size @@ -143,10 +233,10 @@ class FixturesTest < ActiveRecord::TestCase ] } - conn.stubs(:max_allowed_packet).returns(packet_size) - - assert_difference "TrafficLight.count" do - conn.insert_fixtures_set(fixtures) + conn.stub(:max_allowed_packet, packet_size) do + assert_difference "TrafficLight.count" do + conn.insert_fixtures_set(fixtures) + end end end @@ -164,12 +254,13 @@ class FixturesTest < ActiveRecord::TestCase ] } - conn.stubs(:max_allowed_packet).returns(packet_size) + conn.stub(:max_allowed_packet, packet_size) do + conn.insert_fixtures_set(fixtures) - conn.insert_fixtures_set(fixtures) - assert_equal 2, subscriber.events.size - assert_operator subscriber.events.first.bytesize, :<, packet_size - assert_operator subscriber.events.second.bytesize, :<, packet_size + assert_equal 2, subscriber.events.size + assert_operator subscriber.events.first.bytesize, :<, packet_size + assert_operator subscriber.events.second.bytesize, :<, packet_size + end ensure ActiveSupport::Notifications.unsubscribe(subscription) end @@ -188,10 +279,10 @@ class FixturesTest < ActiveRecord::TestCase ] } - conn.stubs(:max_allowed_packet).returns(packet_size) - - assert_difference ["TrafficLight.count", "Comment.count"], +1 do - conn.insert_fixtures_set(fixtures) + conn.stub(:max_allowed_packet, packet_size) do + assert_difference ["TrafficLight.count", "Comment.count"], +1 do + conn.insert_fixtures_set(fixtures) + end end assert_equal 1, subscriber.events.size ensure @@ -833,44 +924,58 @@ class TransactionalFixturesOnConnectionNotification < ActiveRecord::TestCase self.use_instantiated_fixtures = false def test_transaction_created_on_connection_notification - connection = stub(transaction_open?: false) - connection.expects(:begin_transaction).with(joinable: false) - pool = connection.stubs(:pool).returns(ActiveRecord::ConnectionAdapters::ConnectionPool.new(ActiveRecord::Base.connection_pool.spec)) - pool.stubs(:lock_thread=).with(false) - fire_connection_notification(connection) + connection = Class.new do + attr_accessor :pool + + def transaction_open?; end + def begin_transaction(*args); end + def rollback_transaction(*args); end + end.new + + connection.pool = Class.new do + def lock_thread=(lock_thread); end + end.new + + assert_called_with(connection, :begin_transaction, [joinable: false]) do + fire_connection_notification(connection) + end end def test_notification_established_transactions_are_rolled_back - # Mocha is not thread-safe so define our own stub to test connection = Class.new do attr_accessor :rollback_transaction_called attr_accessor :pool + def transaction_open?; true; end def begin_transaction(*args); end def rollback_transaction(*args) @rollback_transaction_called = true end end.new + connection.pool = Class.new do - def lock_thread=(lock_thread); false; end + def lock_thread=(lock_thread); end end.new + fire_connection_notification(connection) teardown_fixtures + assert(connection.rollback_transaction_called, "Expected <mock connection>#rollback_transaction to be called but was not") end private def fire_connection_notification(connection) - ActiveRecord::Base.connection_handler.stubs(:retrieve_connection).with("book").returns(connection) - message_bus = ActiveSupport::Notifications.instrumenter - payload = { - spec_name: "book", - config: nil, - connection_id: connection.object_id - } + assert_called_with(ActiveRecord::Base.connection_handler, :retrieve_connection, ["book"], returns: connection) do + message_bus = ActiveSupport::Notifications.instrumenter + payload = { + spec_name: "book", + config: nil, + connection_id: connection.object_id + } - message_bus.instrument("!connection.active_record", payload) {} + message_bus.instrument("!connection.active_record", payload) {} + end end end diff --git a/activerecord/test/cases/inheritance_test.rb b/activerecord/test/cases/inheritance_test.rb index 4a0ad0442a..3d3189900f 100644 --- a/activerecord/test/cases/inheritance_test.rb +++ b/activerecord/test/cases/inheritance_test.rb @@ -91,7 +91,6 @@ class InheritanceTest < ActiveRecord::TestCase end ActiveSupport::Dependencies.stub(:safe_constantize, proc { raise e }) do - exception = assert_raises NameError do Company.send :compute_type, "InvalidModel" end diff --git a/activerecord/test/cases/locking_test.rb b/activerecord/test/cases/locking_test.rb index 8513edb0ab..33bd74e114 100644 --- a/activerecord/test/cases/locking_test.rb +++ b/activerecord/test/cases/locking_test.rb @@ -445,32 +445,38 @@ class OptimisticLockingTest < ActiveRecord::TestCase assert_equal 0, car.wheels_count assert_equal 0, car.lock_version - previously_car_updated_at = car.updated_at - travel(2.second) do + previously_updated_at = car.updated_at + previously_wheels_owned_at = car.wheels_owned_at + travel(1.second) do Wheel.create!(wheelable: car) end assert_equal 1, car.reload.wheels_count - assert_not_equal previously_car_updated_at, car.updated_at assert_equal 1, car.lock_version + assert_operator previously_updated_at, :<, car.updated_at + assert_operator previously_wheels_owned_at, :<, car.wheels_owned_at - previously_car_updated_at = car.updated_at - travel(1.day) do + previously_updated_at = car.updated_at + previously_wheels_owned_at = car.wheels_owned_at + travel(2.second) do car.wheels.first.update(size: 42) end assert_equal 1, car.reload.wheels_count - assert_not_equal previously_car_updated_at, car.updated_at assert_equal 2, car.lock_version + assert_operator previously_updated_at, :<, car.updated_at + assert_operator previously_wheels_owned_at, :<, car.wheels_owned_at - previously_car_updated_at = car.updated_at - travel(2.second) do + previously_updated_at = car.updated_at + previously_wheels_owned_at = car.wheels_owned_at + travel(3.second) do car.wheels.first.destroy! end assert_equal 0, car.reload.wheels_count - assert_not_equal previously_car_updated_at, car.updated_at assert_equal 3, car.lock_version + assert_operator previously_updated_at, :<, car.updated_at + assert_operator previously_wheels_owned_at, :<, car.wheels_owned_at end def test_polymorphic_destroy_with_dependencies_and_lock_version diff --git a/activerecord/test/cases/migration/change_schema_test.rb b/activerecord/test/cases/migration/change_schema_test.rb index f4d16cb093..7777508349 100644 --- a/activerecord/test/cases/migration/change_schema_test.rb +++ b/activerecord/test/cases/migration/change_schema_test.rb @@ -196,6 +196,17 @@ module ActiveRecord assert_equal "you can't redefine the primary key column 'testing_id'. To define a custom primary key, pass { id: false } to create_table.", error.message end + def test_create_table_raises_when_defining_existing_column + error = assert_raise(ArgumentError) do + connection.create_table :testings do |t| + t.column :testing_column, :string + t.column :testing_column, :integer + end + end + + assert_equal "you can't define an already defined column 'testing_column'.", error.message + end + def test_create_table_with_timestamps_should_create_datetime_columns connection.create_table table_name do |t| t.timestamps diff --git a/activerecord/test/cases/nested_attributes_test.rb b/activerecord/test/cases/nested_attributes_test.rb index 32af90caef..ec01a2965d 100644 --- a/activerecord/test/cases/nested_attributes_test.rb +++ b/activerecord/test/cases/nested_attributes_test.rb @@ -669,7 +669,6 @@ module NestedAttributesOnACollectionAssociationTests def test_should_take_a_hash_with_composite_id_keys_and_assign_the_attributes_to_the_associated_models @child_1.stub(:id, "ABC1X") do @child_2.stub(:id, "ABC2X") do - @pirate.attributes = { association_getter => [ { id: @child_1.id, name: "Grace OMalley" }, diff --git a/activerecord/test/cases/persistence_test.rb b/activerecord/test/cases/persistence_test.rb index 4c332e30aa..7348a22dd3 100644 --- a/activerecord/test/cases/persistence_test.rb +++ b/activerecord/test/cases/persistence_test.rb @@ -206,12 +206,28 @@ class PersistenceTest < ActiveRecord::TestCase assert_equal initial_credit + 2, a1.reload.credit_limit end - def test_increment_updates_timestamps + def test_increment_with_touch_updates_timestamps topic = topics(:first) - topic.update_columns(updated_at: 5.minutes.ago) - previous_updated_at = topic.updated_at - topic.increment!(:replies_count, touch: true) - assert_operator previous_updated_at, :<, topic.reload.updated_at + assert_equal 1, topic.replies_count + previously_updated_at = topic.updated_at + travel(1.second) do + topic.increment!(:replies_count, touch: true) + end + assert_equal 2, topic.reload.replies_count + assert_operator previously_updated_at, :<, topic.updated_at + end + + def test_increment_with_touch_an_attribute_updates_timestamps + topic = topics(:first) + assert_equal 1, topic.replies_count + previously_updated_at = topic.updated_at + previously_written_on = topic.written_on + travel(1.second) do + topic.increment!(:replies_count, touch: :written_on) + end + assert_equal 2, topic.reload.replies_count + assert_operator previously_updated_at, :<, topic.updated_at + assert_operator previously_written_on, :<, topic.written_on end def test_destroy_all @@ -333,12 +349,28 @@ class PersistenceTest < ActiveRecord::TestCase assert_equal 41, accounts(:signals37, :reload).credit_limit end - def test_decrement_updates_timestamps + def test_decrement_with_touch_updates_timestamps topic = topics(:first) - topic.update_columns(updated_at: 5.minutes.ago) - previous_updated_at = topic.updated_at - topic.decrement!(:replies_count, touch: true) - assert_operator previous_updated_at, :<, topic.reload.updated_at + assert_equal 1, topic.replies_count + previously_updated_at = topic.updated_at + travel(1.second) do + topic.decrement!(:replies_count, touch: true) + end + assert_equal 0, topic.reload.replies_count + assert_operator previously_updated_at, :<, topic.updated_at + end + + def test_decrement_with_touch_an_attribute_updates_timestamps + topic = topics(:first) + assert_equal 1, topic.replies_count + previously_updated_at = topic.updated_at + previously_written_on = topic.written_on + travel(1.second) do + topic.decrement!(:replies_count, touch: :written_on) + end + assert_equal 0, topic.reload.replies_count + assert_operator previously_updated_at, :<, topic.updated_at + assert_operator previously_written_on, :<, topic.written_on end def test_create diff --git a/activerecord/test/cases/primary_keys_test.rb b/activerecord/test/cases/primary_keys_test.rb index 60dac91ec9..4ed7469039 100644 --- a/activerecord/test/cases/primary_keys_test.rb +++ b/activerecord/test/cases/primary_keys_test.rb @@ -305,6 +305,7 @@ class PrimaryKeyAnyTypeTest < ActiveRecord::TestCase test "schema dump primary key includes type and options" do schema = dump_table_schema "barcodes" assert_match %r{create_table "barcodes", primary_key: "code", id: :string, limit: 42}, schema + assert_no_match %r{t\.index \["code"\]}, schema end if current_adapter?(:Mysql2Adapter) && subsecond_precision_supported? diff --git a/activerecord/test/cases/query_cache_test.rb b/activerecord/test/cases/query_cache_test.rb index 0f990bac9d..69be091869 100644 --- a/activerecord/test/cases/query_cache_test.rb +++ b/activerecord/test/cases/query_cache_test.rb @@ -13,12 +13,13 @@ class QueryCacheTest < ActiveRecord::TestCase fixtures :tasks, :topics, :categories, :posts, :categories_posts class ShouldNotHaveExceptionsLogger < ActiveRecord::LogSubscriber - attr_reader :logger + attr_reader :logger, :events def initialize super @logger = ::Logger.new File::NULL @exception = false + @events = [] end def exception? @@ -26,6 +27,7 @@ class QueryCacheTest < ActiveRecord::TestCase end def sql(event) + @events << event super rescue @exception = true @@ -265,6 +267,26 @@ class QueryCacheTest < ActiveRecord::TestCase end end + def test_cache_notifications_can_be_overridden + logger = ShouldNotHaveExceptionsLogger.new + subscriber = ActiveSupport::Notifications.subscribe "sql.active_record", logger + + connection = ActiveRecord::Base.connection.dup + + def connection.cache_notification_info(sql, name, binds) + super.merge(neat: true) + end + + connection.cache do + connection.select_all "select 1" + connection.select_all "select 1" + end + + assert_equal true, logger.events.last.payload[:neat] + ensure + ActiveSupport::Notifications.unsubscribe subscriber + end + def test_cache_does_not_raise_exceptions logger = ShouldNotHaveExceptionsLogger.new subscriber = ActiveSupport::Notifications.subscribe "sql.active_record", logger @@ -460,7 +482,6 @@ class QueryCacheTest < ActiveRecord::TestCase assert_not ActiveRecord::Base.connection.query_cache_enabled }.join }.call({}) - end end diff --git a/activerecord/test/cases/quoting_test.rb b/activerecord/test/cases/quoting_test.rb index 92eb0c814f..f875dc96f7 100644 --- a/activerecord/test/cases/quoting_test.rb +++ b/activerecord/test/cases/quoting_test.rb @@ -71,8 +71,8 @@ module ActiveRecord with_timezone_config default: :utc do t = Time.now.change(usec: 0) - expected = t.getutc.change(year: 2000, month: 1, day: 1) - expected = expected.to_s(:db).sub("2000-01-01 ", "") + expected = t.change(year: 2000, month: 1, day: 1) + expected = expected.getutc.to_s(:db).slice(11..-1) assert_equal expected, @quoter.quoted_time(t) end @@ -89,6 +89,28 @@ module ActiveRecord end end + def test_quoted_time_dst_utc + with_timezone_config default: :utc do + t = Time.new(2000, 7, 1, 0, 0, 0, "+04:30") + + expected = t.change(year: 2000, month: 1, day: 1) + expected = expected.getutc.to_s(:db).slice(11..-1) + + assert_equal expected, @quoter.quoted_time(t) + end + end + + def test_quoted_time_dst_local + with_timezone_config default: :local do + t = Time.new(2000, 7, 1, 0, 0, 0, "+04:30") + + expected = t.change(year: 2000, month: 1, day: 1) + expected = expected.getlocal.to_s(:db).slice(11..-1) + + assert_equal expected, @quoter.quoted_time(t) + end + end + def test_quoted_time_crazy with_timezone_config default: :asdfasdf do t = Time.now.change(usec: 0) diff --git a/activerecord/test/cases/relation_test.rb b/activerecord/test/cases/relation_test.rb index 93e2363025..fbeb617b29 100644 --- a/activerecord/test/cases/relation_test.rb +++ b/activerecord/test/cases/relation_test.rb @@ -5,10 +5,11 @@ require "models/post" require "models/comment" require "models/author" require "models/rating" +require "models/categorization" module ActiveRecord class RelationTest < ActiveRecord::TestCase - fixtures :posts, :comments, :authors, :author_addresses, :ratings + fixtures :posts, :comments, :authors, :author_addresses, :ratings, :categorizations def test_construction relation = Relation.new(FakeKlass, table: :b) @@ -223,6 +224,30 @@ module ActiveRecord assert_equal manual_comments_on_post_that_have_author.size, merged_authors_with_commented_posts_relation.to_a.size end + def test_relation_merging_with_merged_symbol_joins_is_aliased + categorizations_with_authors = Categorization.joins(:author) + queries = capture_sql { Post.joins(:author, :categorizations).merge(Author.select(:id)).merge(categorizations_with_authors).to_a } + + nb_inner_join = queries.sum { |sql| sql.scan(/INNER\s+JOIN/i).size } + assert_equal 3, nb_inner_join, "Wrong amount of INNER JOIN in query" + + # using `\W` as the column separator + assert queries.any? { |sql| %r[INNER\s+JOIN\s+#{Author.quoted_table_name}\s+\Wauthors_categorizations\W]i.match?(sql) }, "Should be aliasing the child INNER JOINs in query" + end + + def test_relation_with_merged_joins_aliased_works + categorizations_with_authors = Categorization.joins(:author) + posts_with_joins_and_merges = Post.joins(:author, :categorizations) + .merge(Author.select(:id)).merge(categorizations_with_authors) + + author_with_posts = Author.joins(:posts).ids + categorizations_with_author = Categorization.joins(:author).ids + posts_with_author_and_categorizations = Post.joins(:categorizations).where(author_id: author_with_posts, categorizations: { id: categorizations_with_author }).ids + + assert_equal posts_with_author_and_categorizations.size, posts_with_joins_and_merges.count + assert_equal posts_with_author_and_categorizations.size, posts_with_joins_and_merges.to_a.size + end + def test_relation_merging_with_joins_as_join_dependency_pick_proper_parent post = Post.create!(title: "haha", body: "huhu") comment = post.comments.create!(body: "hu") diff --git a/activerecord/test/cases/result_test.rb b/activerecord/test/cases/result_test.rb index db52c108ac..68fcafb682 100644 --- a/activerecord/test/cases/result_test.rb +++ b/activerecord/test/cases/result_test.rb @@ -12,6 +12,11 @@ module ActiveRecord ]) end + test "includes_column?" do + assert result.includes_column?("col_1") + assert_not result.includes_column?("foo") + end + test "length" do assert_equal 3, result.length end diff --git a/activerecord/test/cases/schema_dumper_test.rb b/activerecord/test/cases/schema_dumper_test.rb index 15f4cea1a6..75b68b521c 100644 --- a/activerecord/test/cases/schema_dumper_test.rb +++ b/activerecord/test/cases/schema_dumper_test.rb @@ -297,29 +297,33 @@ class SchemaDumperTest < ActiveRecord::TestCase def test_schema_dump_includes_extensions connection = ActiveRecord::Base.connection - connection.stubs(:extensions).returns(["hstore"]) - output = perform_schema_dump - assert_match "# These are extensions that must be enabled", output - assert_match %r{enable_extension "hstore"}, output - - connection.stubs(:extensions).returns([]) - output = perform_schema_dump - assert_no_match "# These are extensions that must be enabled", output - assert_no_match %r{enable_extension}, output + connection.stub(:extensions, ["hstore"]) do + output = perform_schema_dump + assert_match "# These are extensions that must be enabled", output + assert_match %r{enable_extension "hstore"}, output + end + + connection.stub(:extensions, []) do + output = perform_schema_dump + assert_no_match "# These are extensions that must be enabled", output + assert_no_match %r{enable_extension}, output + end end def test_schema_dump_includes_extensions_in_alphabetic_order connection = ActiveRecord::Base.connection - connection.stubs(:extensions).returns(["hstore", "uuid-ossp", "xml2"]) - output = perform_schema_dump - enabled_extensions = output.scan(%r{enable_extension "(.+)"}).flatten - assert_equal ["hstore", "uuid-ossp", "xml2"], enabled_extensions + connection.stub(:extensions, ["hstore", "uuid-ossp", "xml2"]) do + output = perform_schema_dump + enabled_extensions = output.scan(%r{enable_extension "(.+)"}).flatten + assert_equal ["hstore", "uuid-ossp", "xml2"], enabled_extensions + end - connection.stubs(:extensions).returns(["uuid-ossp", "xml2", "hstore"]) - output = perform_schema_dump - enabled_extensions = output.scan(%r{enable_extension "(.+)"}).flatten - assert_equal ["hstore", "uuid-ossp", "xml2"], enabled_extensions + connection.stub(:extensions, ["uuid-ossp", "xml2", "hstore"]) do + output = perform_schema_dump + enabled_extensions = output.scan(%r{enable_extension "(.+)"}).flatten + assert_equal ["hstore", "uuid-ossp", "xml2"], enabled_extensions + end end end diff --git a/activerecord/test/cases/scoping/relation_scoping_test.rb b/activerecord/test/cases/scoping/relation_scoping_test.rb index f18f1ed981..544adc9b39 100644 --- a/activerecord/test/cases/scoping/relation_scoping_test.rb +++ b/activerecord/test/cases/scoping/relation_scoping_test.rb @@ -254,6 +254,11 @@ class RelationScopingTest < ActiveRecord::TestCase end end + def test_scoping_works_in_the_scope_block + expected = SpecialPostWithDefaultScope.unscoped.to_a + assert_equal expected, SpecialPostWithDefaultScope.unscoped_all + end + def test_circular_joins_with_scoping_does_not_crash posts = Post.joins(comments: :post).scoping do Post.first(10) diff --git a/activerecord/test/cases/serialized_attribute_test.rb b/activerecord/test/cases/serialized_attribute_test.rb index 7de5429cbb..4cd4515c3b 100644 --- a/activerecord/test/cases/serialized_attribute_test.rb +++ b/activerecord/test/cases/serialized_attribute_test.rb @@ -159,6 +159,13 @@ class SerializedAttributeTest < ActiveRecord::TestCase assert_equal(settings, Topic.find(topic.id).content) end + def test_where_by_serialized_attribute_with_array + settings = [ "color" => "green" ] + Topic.serialize(:content, Array) + topic = Topic.create!(content: settings) + assert_equal topic, Topic.where(content: settings).take + end + def test_where_by_serialized_attribute_with_hash settings = { "color" => "green" } Topic.serialize(:content, Hash) @@ -166,6 +173,13 @@ class SerializedAttributeTest < ActiveRecord::TestCase assert_equal topic, Topic.where(content: settings).take end + def test_where_by_serialized_attribute_with_hash_in_array + settings = { "color" => "green" } + Topic.serialize(:content, Hash) + topic = Topic.create!(content: settings) + assert_equal topic, Topic.where(content: [settings]).take + end + def test_serialized_default_class Topic.serialize(:content, Hash) topic = Topic.new diff --git a/activerecord/test/cases/store_test.rb b/activerecord/test/cases/store_test.rb index 3bd480cfbd..4457cfbd37 100644 --- a/activerecord/test/cases/store_test.rb +++ b/activerecord/test/cases/store_test.rb @@ -214,4 +214,38 @@ class StoreTest < ActiveRecord::TestCase second_dump = YAML.dump(loaded) assert_equal @john, YAML.load(second_dump) end + + test "read store attributes through accessors with default suffix" do + @john.configs[:two_factor_auth] = true + assert_equal true, @john.two_factor_auth_configs + end + + test "write store attributes through accessors with default suffix" do + @john.two_factor_auth_configs = false + assert_equal false, @john.configs[:two_factor_auth] + end + + test "read store attributes through accessors with custom suffix" do + @john.configs[:login_retry] = 3 + assert_equal 3, @john.login_retry_config + end + + test "write store attributes through accessors with custom suffix" do + @john.login_retry_config = 5 + assert_equal 5, @john.configs[:login_retry] + end + + test "read accessor without pre/suffix in the same store as other pre/suffixed accessors still works" do + @john.configs[:secret_question] = "What is your high school?" + assert_equal "What is your high school?", @john.secret_question + end + + test "write accessor without pre/suffix in the same store as other pre/suffixed accessors still works" do + @john.secret_question = "What was the Rails version when you first worked on it?" + assert_equal "What was the Rails version when you first worked on it?", @john.configs[:secret_question] + end + + test "prefix/suffix do not affect stored attributes" do + assert_equal [:secret_question, :two_factor_auth, :login_retry], Admin::User.stored_attributes[:configs] + end end diff --git a/activerecord/test/cases/tasks/database_tasks_test.rb b/activerecord/test/cases/tasks/database_tasks_test.rb index 60c7cb1bb4..1f79f1a630 100644 --- a/activerecord/test/cases/tasks/database_tasks_test.rb +++ b/activerecord/test/cases/tasks/database_tasks_test.rb @@ -6,10 +6,18 @@ require "active_record/tasks/database_tasks" module ActiveRecord module DatabaseTasksSetupper def setup - @mysql_tasks, @postgresql_tasks, @sqlite_tasks = stub, stub, stub - ActiveRecord::Tasks::MySQLDatabaseTasks.stubs(:new).returns @mysql_tasks - ActiveRecord::Tasks::PostgreSQLDatabaseTasks.stubs(:new).returns @postgresql_tasks - ActiveRecord::Tasks::SQLiteDatabaseTasks.stubs(:new).returns @sqlite_tasks + @mysql_tasks, @postgresql_tasks, @sqlite_tasks = Array.new( + 3, + Class.new do + def create; end + def drop; end + def purge; end + def charset; end + def collation; end + def structure_dump(*); end + def structure_load(*); end + end.new + ) $stdout, @original_stdout = StringIO.new, $stdout $stderr, @original_stderr = StringIO.new, $stderr @@ -18,6 +26,16 @@ module ActiveRecord def teardown $stdout, $stderr = @original_stdout, @original_stderr end + + def with_stubbed_new + ActiveRecord::Tasks::MySQLDatabaseTasks.stub(:new, @mysql_tasks) do + ActiveRecord::Tasks::PostgreSQLDatabaseTasks.stub(:new, @postgresql_tasks) do + ActiveRecord::Tasks::SQLiteDatabaseTasks.stub(:new, @sqlite_tasks) do + yield + end + end + end + end end ADAPTERS_TASKS = { @@ -37,6 +55,7 @@ module ActiveRecord ActiveRecord::Tasks::DatabaseTasks.check_protected_environments! ActiveRecord::Base.protected_environments = [current_env] + assert_raise(ActiveRecord::ProtectedEnvironmentError) do ActiveRecord::Tasks::DatabaseTasks.check_protected_environments! end @@ -62,11 +81,12 @@ module ActiveRecord end def test_raises_an_error_if_no_migrations_have_been_made - ActiveRecord::InternalMetadata.stubs(:table_exists?).returns(false) - ActiveRecord::MigrationContext.any_instance.stubs(:current_version).returns(1) + ActiveRecord::InternalMetadata.stub(:table_exists?, false) do + ActiveRecord::MigrationContext.any_instance.stubs(:current_version).returns(1) - assert_raise(ActiveRecord::NoEnvironmentInSchemaError) do - ActiveRecord::Tasks::DatabaseTasks.check_protected_environments! + assert_raise(ActiveRecord::NoEnvironmentInSchemaError) do + ActiveRecord::Tasks::DatabaseTasks.check_protected_environments! + end end end end @@ -79,11 +99,11 @@ module ActiveRecord end instance = klazz.new - klazz.stubs(:new).returns instance - - assert_called_with(instance, :structure_dump, ["awesome-file.sql", nil]) do - ActiveRecord::Tasks::DatabaseTasks.register_task(/foo/, klazz) - ActiveRecord::Tasks::DatabaseTasks.structure_dump({ "adapter" => :foo }, "awesome-file.sql") + klazz.stub(:new, instance) do + assert_called_with(instance, :structure_dump, ["awesome-file.sql", nil]) do + ActiveRecord::Tasks::DatabaseTasks.register_task(/foo/, klazz) + ActiveRecord::Tasks::DatabaseTasks.structure_dump({ "adapter" => :foo }, "awesome-file.sql") + end end end @@ -99,8 +119,11 @@ module ActiveRecord ADAPTERS_TASKS.each do |k, v| define_method("test_#{k}_create") do - eval("@#{v}").expects(:create) - ActiveRecord::Tasks::DatabaseTasks.create "adapter" => k + with_stubbed_new do + assert_called(eval("@#{v}"), :create) do + ActiveRecord::Tasks::DatabaseTasks.create "adapter" => k + end + end end end end @@ -120,59 +143,85 @@ module ActiveRecord def setup @configurations = { "development" => { "database" => "my-db" } } - ActiveRecord::Base.stubs(:configurations).returns(@configurations) # To refrain from connecting to a newly created empty DB in sqlite3_mem tests ActiveRecord::Base.connection_handler.stubs(:establish_connection) + + $stdout, @original_stdout = StringIO.new, $stdout + $stderr, @original_stderr = StringIO.new, $stderr + end + + def teardown + $stdout, $stderr = @original_stdout, @original_stderr end def test_ignores_configurations_without_databases @configurations["development"].merge!("database" => nil) - assert_not_called(ActiveRecord::Tasks::DatabaseTasks, :create) do - ActiveRecord::Tasks::DatabaseTasks.create_all + with_stubbed_configurations do + assert_not_called(ActiveRecord::Tasks::DatabaseTasks, :create) do + ActiveRecord::Tasks::DatabaseTasks.create_all + end end end def test_ignores_remote_databases @configurations["development"].merge!("host" => "my.server.tld") - $stderr.stubs(:puts).returns(nil) - assert_not_called(ActiveRecord::Tasks::DatabaseTasks, :create) do - ActiveRecord::Tasks::DatabaseTasks.create_all + with_stubbed_configurations do + assert_not_called(ActiveRecord::Tasks::DatabaseTasks, :create) do + ActiveRecord::Tasks::DatabaseTasks.create_all + end end end def test_warning_for_remote_databases @configurations["development"].merge!("host" => "my.server.tld") - assert_called_with($stderr, :puts, ["This task only modifies local databases. my-db is on a remote host."]) do + with_stubbed_configurations do ActiveRecord::Tasks::DatabaseTasks.create_all + + assert_match "This task only modifies local databases. my-db is on a remote host.", + $stderr.string end end def test_creates_configurations_with_local_ip @configurations["development"].merge!("host" => "127.0.0.1") - assert_called(ActiveRecord::Tasks::DatabaseTasks, :create) do - ActiveRecord::Tasks::DatabaseTasks.create_all + with_stubbed_configurations do + assert_called(ActiveRecord::Tasks::DatabaseTasks, :create) do + ActiveRecord::Tasks::DatabaseTasks.create_all + end end end def test_creates_configurations_with_local_host @configurations["development"].merge!("host" => "localhost") - assert_called(ActiveRecord::Tasks::DatabaseTasks, :create) do - ActiveRecord::Tasks::DatabaseTasks.create_all + with_stubbed_configurations do + assert_called(ActiveRecord::Tasks::DatabaseTasks, :create) do + ActiveRecord::Tasks::DatabaseTasks.create_all + end end end def test_creates_configurations_with_blank_hosts @configurations["development"].merge!("host" => nil) - assert_called(ActiveRecord::Tasks::DatabaseTasks, :create) do - ActiveRecord::Tasks::DatabaseTasks.create_all + with_stubbed_configurations do + assert_called(ActiveRecord::Tasks::DatabaseTasks, :create) do + ActiveRecord::Tasks::DatabaseTasks.create_all + end end end + + private + + def with_stubbed_configurations + ActiveRecord::Base.stub(:configurations, @configurations) do + yield + end + end end class DatabaseTasksCreateCurrentTest < ActiveRecord::TestCase @@ -182,70 +231,94 @@ module ActiveRecord "test" => { "database" => "test-db" }, "production" => { "url" => "prod-db-url" } } - - ActiveRecord::Base.stubs(:configurations).returns(@configurations) - ActiveRecord::Base.stubs(:establish_connection).returns(true) end def test_creates_current_environment_database - assert_called_with( - ActiveRecord::Tasks::DatabaseTasks, - :create, - ["database" => "test-db"], - ) do - ActiveRecord::Tasks::DatabaseTasks.create_current( - ActiveSupport::StringInquirer.new("test") - ) + with_stubbed_configurations_establish_connection do + assert_called_with( + ActiveRecord::Tasks::DatabaseTasks, + :create, + ["database" => "test-db"], + ) do + ActiveRecord::Tasks::DatabaseTasks.create_current( + ActiveSupport::StringInquirer.new("test") + ) + end end end def test_creates_current_environment_database_with_url - assert_called_with( - ActiveRecord::Tasks::DatabaseTasks, - :create, - ["url" => "prod-db-url"], - ) do - ActiveRecord::Tasks::DatabaseTasks.create_current( - ActiveSupport::StringInquirer.new("production") - ) + with_stubbed_configurations_establish_connection do + assert_called_with( + ActiveRecord::Tasks::DatabaseTasks, + :create, + ["url" => "prod-db-url"], + ) do + ActiveRecord::Tasks::DatabaseTasks.create_current( + ActiveSupport::StringInquirer.new("production") + ) + end end end def test_creates_test_and_development_databases_when_env_was_not_specified - ActiveRecord::Tasks::DatabaseTasks.expects(:create). - with("database" => "dev-db") - ActiveRecord::Tasks::DatabaseTasks.expects(:create). - with("database" => "test-db") - - ActiveRecord::Tasks::DatabaseTasks.create_current( - ActiveSupport::StringInquirer.new("development") - ) + with_stubbed_configurations_establish_connection do + assert_called_with( + ActiveRecord::Tasks::DatabaseTasks, + :create, + [ + ["database" => "dev-db"], + ["database" => "test-db"] + ], + ) do + ActiveRecord::Tasks::DatabaseTasks.create_current( + ActiveSupport::StringInquirer.new("development") + ) + end + end end def test_creates_test_and_development_databases_when_rails_env_is_development old_env = ENV["RAILS_ENV"] ENV["RAILS_ENV"] = "development" - ActiveRecord::Tasks::DatabaseTasks.expects(:create). - with("database" => "dev-db") - ActiveRecord::Tasks::DatabaseTasks.expects(:create). - with("database" => "test-db") - ActiveRecord::Tasks::DatabaseTasks.create_current( - ActiveSupport::StringInquirer.new("development") - ) + with_stubbed_configurations_establish_connection do + assert_called_with( + ActiveRecord::Tasks::DatabaseTasks, + :create, + [ + ["database" => "dev-db"], + ["database" => "test-db"] + ], + ) do + ActiveRecord::Tasks::DatabaseTasks.create_current( + ActiveSupport::StringInquirer.new("development") + ) + end + end ensure ENV["RAILS_ENV"] = old_env end def test_establishes_connection_for_the_given_environments - ActiveRecord::Tasks::DatabaseTasks.stubs(:create).returns true + ActiveRecord::Tasks::DatabaseTasks.stub(:create, nil) do + assert_called_with(ActiveRecord::Base, :establish_connection, [:development]) do + ActiveRecord::Tasks::DatabaseTasks.create_current( + ActiveSupport::StringInquirer.new("development") + ) + end + end + end - ActiveRecord::Base.expects(:establish_connection).with(:development) + private - ActiveRecord::Tasks::DatabaseTasks.create_current( - ActiveSupport::StringInquirer.new("development") - ) - end + def with_stubbed_configurations_establish_connection + ActiveRecord::Base.stub(:configurations, @configurations) do + ActiveRecord::Base.stub(:establish_connection, nil) do + yield + end + end + end end class DatabaseTasksCreateCurrentThreeTierTest < ActiveRecord::TestCase @@ -255,78 +328,108 @@ module ActiveRecord "test" => { "primary" => { "database" => "test-db" }, "secondary" => { "database" => "secondary-test-db" } }, "production" => { "primary" => { "url" => "prod-db-url" }, "secondary" => { "url" => "secondary-prod-db-url" } } } - - ActiveRecord::Base.stubs(:configurations).returns(@configurations) - ActiveRecord::Base.stubs(:establish_connection).returns(true) end def test_creates_current_environment_database - ActiveRecord::Tasks::DatabaseTasks.expects(:create). - with("database" => "test-db") - - ActiveRecord::Tasks::DatabaseTasks.expects(:create). - with("database" => "secondary-test-db") - - ActiveRecord::Tasks::DatabaseTasks.create_current( - ActiveSupport::StringInquirer.new("test") - ) + with_stubbed_configurations_establish_connection do + assert_called_with( + ActiveRecord::Tasks::DatabaseTasks, + :create, + [ + ["database" => "test-db"], + ["database" => "secondary-test-db"] + ] + ) do + ActiveRecord::Tasks::DatabaseTasks.create_current( + ActiveSupport::StringInquirer.new("test") + ) + end + end end def test_creates_current_environment_database_with_url - ActiveRecord::Tasks::DatabaseTasks.expects(:create). - with("url" => "prod-db-url") - - ActiveRecord::Tasks::DatabaseTasks.expects(:create). - with("url" => "secondary-prod-db-url") - - ActiveRecord::Tasks::DatabaseTasks.create_current( - ActiveSupport::StringInquirer.new("production") - ) + with_stubbed_configurations_establish_connection do + assert_called_with( + ActiveRecord::Tasks::DatabaseTasks, + :create, + [ + ["url" => "prod-db-url"], + ["url" => "secondary-prod-db-url"] + ] + ) do + ActiveRecord::Tasks::DatabaseTasks.create_current( + ActiveSupport::StringInquirer.new("production") + ) + end + end end def test_creates_test_and_development_databases_when_env_was_not_specified - ActiveRecord::Tasks::DatabaseTasks.expects(:create). - with("database" => "dev-db") - ActiveRecord::Tasks::DatabaseTasks.expects(:create). - with("database" => "secondary-dev-db") - ActiveRecord::Tasks::DatabaseTasks.expects(:create). - with("database" => "test-db") - ActiveRecord::Tasks::DatabaseTasks.expects(:create). - with("database" => "secondary-test-db") - - ActiveRecord::Tasks::DatabaseTasks.create_current( - ActiveSupport::StringInquirer.new("development") - ) + with_stubbed_configurations_establish_connection do + assert_called_with( + ActiveRecord::Tasks::DatabaseTasks, + :create, + [ + ["database" => "dev-db"], + ["database" => "secondary-dev-db"], + ["database" => "test-db"], + ["database" => "secondary-test-db"] + ] + ) do + ActiveRecord::Tasks::DatabaseTasks.create_current( + ActiveSupport::StringInquirer.new("development") + ) + end + end end def test_creates_test_and_development_databases_when_rails_env_is_development old_env = ENV["RAILS_ENV"] ENV["RAILS_ENV"] = "development" - ActiveRecord::Tasks::DatabaseTasks.expects(:create). - with("database" => "dev-db") - ActiveRecord::Tasks::DatabaseTasks.expects(:create). - with("database" => "secondary-dev-db") - ActiveRecord::Tasks::DatabaseTasks.expects(:create). - with("database" => "test-db") - ActiveRecord::Tasks::DatabaseTasks.expects(:create). - with("database" => "secondary-test-db") - - ActiveRecord::Tasks::DatabaseTasks.create_current( - ActiveSupport::StringInquirer.new("development") - ) + + with_stubbed_configurations_establish_connection do + assert_called_with( + ActiveRecord::Tasks::DatabaseTasks, + :create, + [ + ["database" => "dev-db"], + ["database" => "secondary-dev-db"], + ["database" => "test-db"], + ["database" => "secondary-test-db"] + ] + ) do + ActiveRecord::Tasks::DatabaseTasks.create_current( + ActiveSupport::StringInquirer.new("development") + ) + end + end ensure ENV["RAILS_ENV"] = old_env end def test_establishes_connection_for_the_given_environments_config - ActiveRecord::Tasks::DatabaseTasks.stubs(:create).returns true + ActiveRecord::Tasks::DatabaseTasks.stub(:create, nil) do + assert_called_with( + ActiveRecord::Base, + :establish_connection, + [:development] + ) do + ActiveRecord::Tasks::DatabaseTasks.create_current( + ActiveSupport::StringInquirer.new("development") + ) + end + end + end - ActiveRecord::Base.expects(:establish_connection).with(:development) + private - ActiveRecord::Tasks::DatabaseTasks.create_current( - ActiveSupport::StringInquirer.new("development") - ) - end + def with_stubbed_configurations_establish_connection + ActiveRecord::Base.stub(:configurations, @configurations) do + ActiveRecord::Base.stub(:establish_connection, nil) do + yield + end + end + end end class DatabaseTasksDropTest < ActiveRecord::TestCase @@ -334,8 +437,11 @@ module ActiveRecord ADAPTERS_TASKS.each do |k, v| define_method("test_#{k}_drop") do - eval("@#{v}").expects(:drop) - ActiveRecord::Tasks::DatabaseTasks.drop "adapter" => k + with_stubbed_new do + assert_called(eval("@#{v}"), :drop) do + ActiveRecord::Tasks::DatabaseTasks.drop "adapter" => k + end + end end end end @@ -344,59 +450,72 @@ module ActiveRecord def setup @configurations = { development: { "database" => "my-db" } } - ActiveRecord::Base.stubs(:configurations).returns(@configurations) + $stdout, @original_stdout = StringIO.new, $stdout + $stderr, @original_stderr = StringIO.new, $stderr + end + + def teardown + $stdout, $stderr = @original_stdout, @original_stderr end def test_ignores_configurations_without_databases @configurations[:development].merge!("database" => nil) - assert_not_called(ActiveRecord::Tasks::DatabaseTasks, :drop) do - ActiveRecord::Tasks::DatabaseTasks.drop_all + ActiveRecord::Base.stub(:configurations, @configurations) do + assert_not_called(ActiveRecord::Tasks::DatabaseTasks, :drop) do + ActiveRecord::Tasks::DatabaseTasks.drop_all + end end end def test_ignores_remote_databases @configurations[:development].merge!("host" => "my.server.tld") - $stderr.stubs(:puts).returns(nil) - assert_not_called(ActiveRecord::Tasks::DatabaseTasks, :drop) do - ActiveRecord::Tasks::DatabaseTasks.drop_all + ActiveRecord::Base.stub(:configurations, @configurations) do + assert_not_called(ActiveRecord::Tasks::DatabaseTasks, :drop) do + ActiveRecord::Tasks::DatabaseTasks.drop_all + end end end def test_warning_for_remote_databases @configurations[:development].merge!("host" => "my.server.tld") - assert_called_with( - $stderr, - :puts, - ["This task only modifies local databases. my-db is on a remote host."], - ) do + ActiveRecord::Base.stub(:configurations, @configurations) do ActiveRecord::Tasks::DatabaseTasks.drop_all + + assert_match "This task only modifies local databases. my-db is on a remote host.", + $stderr.string end end def test_drops_configurations_with_local_ip @configurations[:development].merge!("host" => "127.0.0.1") - assert_called(ActiveRecord::Tasks::DatabaseTasks, :drop) do - ActiveRecord::Tasks::DatabaseTasks.drop_all + ActiveRecord::Base.stub(:configurations, @configurations) do + assert_called(ActiveRecord::Tasks::DatabaseTasks, :drop) do + ActiveRecord::Tasks::DatabaseTasks.drop_all + end end end def test_drops_configurations_with_local_host @configurations[:development].merge!("host" => "localhost") - assert_called(ActiveRecord::Tasks::DatabaseTasks, :drop) do - ActiveRecord::Tasks::DatabaseTasks.drop_all + ActiveRecord::Base.stub(:configurations, @configurations) do + assert_called(ActiveRecord::Tasks::DatabaseTasks, :drop) do + ActiveRecord::Tasks::DatabaseTasks.drop_all + end end end def test_drops_configurations_with_blank_hosts @configurations[:development].merge!("host" => nil) - assert_called(ActiveRecord::Tasks::DatabaseTasks, :drop) do - ActiveRecord::Tasks::DatabaseTasks.drop_all + ActiveRecord::Base.stub(:configurations, @configurations) do + assert_called(ActiveRecord::Tasks::DatabaseTasks, :drop) do + ActiveRecord::Tasks::DatabaseTasks.drop_all + end end end end @@ -408,50 +527,65 @@ module ActiveRecord "test" => { "database" => "test-db" }, "production" => { "url" => "prod-db-url" } } - - ActiveRecord::Base.stubs(:configurations).returns(@configurations) end def test_drops_current_environment_database - ActiveRecord::Tasks::DatabaseTasks.expects(:drop). - with("database" => "test-db") - - ActiveRecord::Tasks::DatabaseTasks.drop_current( - ActiveSupport::StringInquirer.new("test") - ) + ActiveRecord::Base.stub(:configurations, @configurations) do + assert_called_with(ActiveRecord::Tasks::DatabaseTasks, :drop, + ["database" => "test-db"]) do + ActiveRecord::Tasks::DatabaseTasks.drop_current( + ActiveSupport::StringInquirer.new("test") + ) + end + end end def test_drops_current_environment_database_with_url - ActiveRecord::Tasks::DatabaseTasks.expects(:drop). - with("url" => "prod-db-url") - - ActiveRecord::Tasks::DatabaseTasks.drop_current( - ActiveSupport::StringInquirer.new("production") - ) + ActiveRecord::Base.stub(:configurations, @configurations) do + assert_called_with(ActiveRecord::Tasks::DatabaseTasks, :drop, + ["url" => "prod-db-url"]) do + ActiveRecord::Tasks::DatabaseTasks.drop_current( + ActiveSupport::StringInquirer.new("production") + ) + end + end end def test_drops_test_and_development_databases_when_env_was_not_specified - ActiveRecord::Tasks::DatabaseTasks.expects(:drop). - with("database" => "dev-db") - ActiveRecord::Tasks::DatabaseTasks.expects(:drop). - with("database" => "test-db") - - ActiveRecord::Tasks::DatabaseTasks.drop_current( - ActiveSupport::StringInquirer.new("development") - ) + ActiveRecord::Base.stub(:configurations, @configurations) do + assert_called_with( + ActiveRecord::Tasks::DatabaseTasks, + :drop, + [ + ["database" => "dev-db"], + ["database" => "test-db"] + ] + ) do + ActiveRecord::Tasks::DatabaseTasks.drop_current( + ActiveSupport::StringInquirer.new("development") + ) + end + end end def test_drops_testand_development_databases_when_rails_env_is_development old_env = ENV["RAILS_ENV"] ENV["RAILS_ENV"] = "development" - ActiveRecord::Tasks::DatabaseTasks.expects(:drop). - with("database" => "dev-db") - ActiveRecord::Tasks::DatabaseTasks.expects(:drop). - with("database" => "test-db") - ActiveRecord::Tasks::DatabaseTasks.drop_current( - ActiveSupport::StringInquirer.new("development") - ) + ActiveRecord::Base.stub(:configurations, @configurations) do + assert_called_with( + ActiveRecord::Tasks::DatabaseTasks, + :drop, + [ + ["database" => "dev-db"], + ["database" => "test-db"] + ] + ) do + ActiveRecord::Tasks::DatabaseTasks.drop_current( + ActiveSupport::StringInquirer.new("development") + ) + end + end ensure ENV["RAILS_ENV"] = old_env end @@ -464,64 +598,81 @@ module ActiveRecord "test" => { "primary" => { "database" => "test-db" }, "secondary" => { "database" => "secondary-test-db" } }, "production" => { "primary" => { "url" => "prod-db-url" }, "secondary" => { "url" => "secondary-prod-db-url" } } } - - ActiveRecord::Base.stubs(:configurations).returns(@configurations) end def test_drops_current_environment_database - ActiveRecord::Tasks::DatabaseTasks.expects(:drop). - with("database" => "test-db") - - ActiveRecord::Tasks::DatabaseTasks.expects(:drop). - with("database" => "secondary-test-db") - - ActiveRecord::Tasks::DatabaseTasks.drop_current( - ActiveSupport::StringInquirer.new("test") - ) + ActiveRecord::Base.stub(:configurations, @configurations) do + assert_called_with( + ActiveRecord::Tasks::DatabaseTasks, + :drop, + [ + ["database" => "test-db"], + ["database" => "secondary-test-db"] + ] + ) do + ActiveRecord::Tasks::DatabaseTasks.drop_current( + ActiveSupport::StringInquirer.new("test") + ) + end + end end def test_drops_current_environment_database_with_url - ActiveRecord::Tasks::DatabaseTasks.expects(:drop). - with("url" => "prod-db-url") - - ActiveRecord::Tasks::DatabaseTasks.expects(:drop). - with("url" => "secondary-prod-db-url") - - ActiveRecord::Tasks::DatabaseTasks.drop_current( - ActiveSupport::StringInquirer.new("production") - ) + ActiveRecord::Base.stub(:configurations, @configurations) do + assert_called_with( + ActiveRecord::Tasks::DatabaseTasks, + :drop, + [ + ["url" => "prod-db-url"], + ["url" => "secondary-prod-db-url"] + ] + ) do + ActiveRecord::Tasks::DatabaseTasks.drop_current( + ActiveSupport::StringInquirer.new("production") + ) + end + end end def test_drops_test_and_development_databases_when_env_was_not_specified - ActiveRecord::Tasks::DatabaseTasks.expects(:drop). - with("database" => "dev-db") - ActiveRecord::Tasks::DatabaseTasks.expects(:drop). - with("database" => "secondary-dev-db") - ActiveRecord::Tasks::DatabaseTasks.expects(:drop). - with("database" => "test-db") - ActiveRecord::Tasks::DatabaseTasks.expects(:drop). - with("database" => "secondary-test-db") - - ActiveRecord::Tasks::DatabaseTasks.drop_current( - ActiveSupport::StringInquirer.new("development") - ) + ActiveRecord::Base.stub(:configurations, @configurations) do + assert_called_with( + ActiveRecord::Tasks::DatabaseTasks, + :drop, + [ + ["database" => "dev-db"], + ["database" => "secondary-dev-db"], + ["database" => "test-db"], + ["database" => "secondary-test-db"] + ] + ) do + ActiveRecord::Tasks::DatabaseTasks.drop_current( + ActiveSupport::StringInquirer.new("development") + ) + end + end end def test_drops_testand_development_databases_when_rails_env_is_development old_env = ENV["RAILS_ENV"] ENV["RAILS_ENV"] = "development" - ActiveRecord::Tasks::DatabaseTasks.expects(:drop). - with("database" => "dev-db") - ActiveRecord::Tasks::DatabaseTasks.expects(:drop). - with("database" => "secondary-dev-db") - ActiveRecord::Tasks::DatabaseTasks.expects(:drop). - with("database" => "test-db") - ActiveRecord::Tasks::DatabaseTasks.expects(:drop). - with("database" => "secondary-test-db") - - ActiveRecord::Tasks::DatabaseTasks.drop_current( - ActiveSupport::StringInquirer.new("development") - ) + + ActiveRecord::Base.stub(:configurations, @configurations) do + assert_called_with( + ActiveRecord::Tasks::DatabaseTasks, + :drop, + [ + ["database" => "dev-db"], + ["database" => "secondary-dev-db"], + ["database" => "test-db"], + ["database" => "secondary-test-db"] + ] + ) do + ActiveRecord::Tasks::DatabaseTasks.drop_current( + ActiveSupport::StringInquirer.new("development") + ) + end + end ensure ENV["RAILS_ENV"] = old_env end @@ -649,10 +800,10 @@ module ActiveRecord end def test_migrate_raise_error_on_failed_check_target_version - ActiveRecord::Tasks::DatabaseTasks.stubs(:check_target_version).raises("foo") - - e = assert_raise(RuntimeError) { ActiveRecord::Tasks::DatabaseTasks.migrate } - assert_equal "foo", e.message + ActiveRecord::Tasks::DatabaseTasks.stub(:check_target_version, -> { raise "foo" }) do + e = assert_raise(RuntimeError) { ActiveRecord::Tasks::DatabaseTasks.migrate } + assert_equal "foo", e.message + end end def test_migrate_clears_schema_cache_afterward @@ -667,8 +818,11 @@ module ActiveRecord ADAPTERS_TASKS.each do |k, v| define_method("test_#{k}_purge") do - eval("@#{v}").expects(:purge) - ActiveRecord::Tasks::DatabaseTasks.purge "adapter" => k + with_stubbed_new do + assert_called(eval("@#{v}"), :purge) do + ActiveRecord::Tasks::DatabaseTasks.purge "adapter" => k + end + end end end end @@ -680,13 +834,16 @@ module ActiveRecord "test" => { "database" => "test-db" }, "production" => { "database" => "prod-db" } } - ActiveRecord::Base.stubs(:configurations).returns(configurations) - - ActiveRecord::Tasks::DatabaseTasks.expects(:purge). - with("database" => "prod-db") - - assert_called_with(ActiveRecord::Base, :establish_connection, [:production]) do - ActiveRecord::Tasks::DatabaseTasks.purge_current("production") + ActiveRecord::Base.stub(:configurations, configurations) do + assert_called_with( + ActiveRecord::Tasks::DatabaseTasks, + :purge, + ["database" => "prod-db"] + ) do + assert_called_with(ActiveRecord::Base, :establish_connection, [:production]) do + ActiveRecord::Tasks::DatabaseTasks.purge_current("production") + end + end end end end @@ -694,12 +851,15 @@ module ActiveRecord class DatabaseTasksPurgeAllTest < ActiveRecord::TestCase def test_purge_all_local_configurations configurations = { development: { "database" => "my-db" } } - ActiveRecord::Base.stubs(:configurations).returns(configurations) - - ActiveRecord::Tasks::DatabaseTasks.expects(:purge). - with("database" => "my-db") - - ActiveRecord::Tasks::DatabaseTasks.purge_all + ActiveRecord::Base.stub(:configurations, configurations) do + assert_called_with( + ActiveRecord::Tasks::DatabaseTasks, + :purge, + ["database" => "my-db"] + ) do + ActiveRecord::Tasks::DatabaseTasks.purge_all + end + end end end @@ -708,8 +868,11 @@ module ActiveRecord ADAPTERS_TASKS.each do |k, v| define_method("test_#{k}_charset") do - eval("@#{v}").expects(:charset) - ActiveRecord::Tasks::DatabaseTasks.charset "adapter" => k + with_stubbed_new do + assert_called(eval("@#{v}"), :charset) do + ActiveRecord::Tasks::DatabaseTasks.charset "adapter" => k + end + end end end end @@ -719,8 +882,11 @@ module ActiveRecord ADAPTERS_TASKS.each do |k, v| define_method("test_#{k}_collation") do - eval("@#{v}").expects(:collation) - ActiveRecord::Tasks::DatabaseTasks.collation "adapter" => k + with_stubbed_new do + assert_called(eval("@#{v}"), :collation) do + ActiveRecord::Tasks::DatabaseTasks.collation "adapter" => k + end + end end end end @@ -832,8 +998,14 @@ module ActiveRecord ADAPTERS_TASKS.each do |k, v| define_method("test_#{k}_structure_dump") do - eval("@#{v}").expects(:structure_dump).with("awesome-file.sql", nil) - ActiveRecord::Tasks::DatabaseTasks.structure_dump({ "adapter" => k }, "awesome-file.sql") + with_stubbed_new do + assert_called_with( + eval("@#{v}"), :structure_dump, + ["awesome-file.sql", nil] + ) do + ActiveRecord::Tasks::DatabaseTasks.structure_dump({ "adapter" => k }, "awesome-file.sql") + end + end end end end @@ -843,8 +1015,15 @@ module ActiveRecord ADAPTERS_TASKS.each do |k, v| define_method("test_#{k}_structure_load") do - eval("@#{v}").expects(:structure_load).with("awesome-file.sql", nil) - ActiveRecord::Tasks::DatabaseTasks.structure_load({ "adapter" => k }, "awesome-file.sql") + with_stubbed_new do + assert_called_with( + eval("@#{v}"), + :structure_load, + ["awesome-file.sql", nil] + ) do + ActiveRecord::Tasks::DatabaseTasks.structure_load({ "adapter" => k }, "awesome-file.sql") + end + end end end end @@ -859,16 +1038,18 @@ module ActiveRecord class DatabaseTasksCheckSchemaFileDefaultsTest < ActiveRecord::TestCase def test_check_schema_file_defaults - ActiveRecord::Tasks::DatabaseTasks.stubs(:db_dir).returns("/tmp") - assert_equal "/tmp/schema.rb", ActiveRecord::Tasks::DatabaseTasks.schema_file + ActiveRecord::Tasks::DatabaseTasks.stub(:db_dir, "/tmp") do + assert_equal "/tmp/schema.rb", ActiveRecord::Tasks::DatabaseTasks.schema_file + end end end class DatabaseTasksCheckSchemaFileSpecifiedFormatsTest < ActiveRecord::TestCase { ruby: "schema.rb", sql: "structure.sql" }.each_pair do |fmt, filename| define_method("test_check_schema_file_for_#{fmt}_format") do - ActiveRecord::Tasks::DatabaseTasks.stubs(:db_dir).returns("/tmp") - assert_equal "/tmp/#{filename}", ActiveRecord::Tasks::DatabaseTasks.schema_file(fmt) + ActiveRecord::Tasks::DatabaseTasks.stub(:db_dir, "/tmp") do + assert_equal "/tmp/#{filename}", ActiveRecord::Tasks::DatabaseTasks.schema_file(fmt) + end end end end diff --git a/activerecord/test/cases/tasks/mysql_rake_test.rb b/activerecord/test/cases/tasks/mysql_rake_test.rb index 6cddfaefeb..a86ddd3c16 100644 --- a/activerecord/test/cases/tasks/mysql_rake_test.rb +++ b/activerecord/test/cases/tasks/mysql_rake_test.rb @@ -7,15 +7,11 @@ if current_adapter?(:Mysql2Adapter) module ActiveRecord class MysqlDBCreateTest < ActiveRecord::TestCase def setup - @connection = stub(create_database: true) + @connection = Class.new { def create_database(*); end }.new @configuration = { "adapter" => "mysql2", "database" => "my-app-db" } - - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection).returns(true) - $stdout, @original_stdout = StringIO.new, $stdout $stderr, @original_stderr = StringIO.new, $stderr end @@ -25,59 +21,86 @@ if current_adapter?(:Mysql2Adapter) end def test_establishes_connection_without_database - ActiveRecord::Base.expects(:establish_connection). - with("adapter" => "mysql2", "database" => nil) - - ActiveRecord::Tasks::DatabaseTasks.create @configuration + ActiveRecord::Base.stubs(:establish_connection) + ActiveRecord::Base.stub(:connection, @connection) do + ActiveRecord::Base.expects(:establish_connection). + with("adapter" => "mysql2", "database" => nil) + ActiveRecord::Tasks::DatabaseTasks.create @configuration + end end def test_creates_database_with_no_default_options - @connection.expects(:create_database). - with("my-app-db", {}) - - ActiveRecord::Tasks::DatabaseTasks.create @configuration + with_stubbed_connection_establish_connection do + assert_called_with(@connection, :create_database, ["my-app-db", {}]) do + ActiveRecord::Tasks::DatabaseTasks.create @configuration + end + end end def test_creates_database_with_given_encoding - @connection.expects(:create_database). - with("my-app-db", charset: "latin1") - - ActiveRecord::Tasks::DatabaseTasks.create @configuration.merge("encoding" => "latin1") + with_stubbed_connection_establish_connection do + assert_called_with(@connection, :create_database, ["my-app-db", charset: "latin1"]) do + ActiveRecord::Tasks::DatabaseTasks.create @configuration.merge("encoding" => "latin1") + end + end end def test_creates_database_with_given_collation - @connection.expects(:create_database). - with("my-app-db", collation: "latin1_swedish_ci") - - ActiveRecord::Tasks::DatabaseTasks.create @configuration.merge("collation" => "latin1_swedish_ci") + with_stubbed_connection_establish_connection do + assert_called_with( + @connection, + :create_database, + ["my-app-db", collation: "latin1_swedish_ci"] + ) do + ActiveRecord::Tasks::DatabaseTasks.create @configuration.merge("collation" => "latin1_swedish_ci") + end + end end def test_establishes_connection_to_database - ActiveRecord::Base.expects(:establish_connection).with(@configuration) + ActiveRecord::Base.stubs(:establish_connection) - ActiveRecord::Tasks::DatabaseTasks.create @configuration + ActiveRecord::Base.stub(:connection, @connection) do + ActiveRecord::Base.expects(:establish_connection).with(@configuration) + + ActiveRecord::Tasks::DatabaseTasks.create @configuration + end end def test_when_database_created_successfully_outputs_info_to_stdout - ActiveRecord::Tasks::DatabaseTasks.create @configuration + with_stubbed_connection_establish_connection do + ActiveRecord::Tasks::DatabaseTasks.create @configuration - assert_equal "Created database 'my-app-db'\n", $stdout.string + assert_equal "Created database 'my-app-db'\n", $stdout.string + end end def test_create_when_database_exists_outputs_info_to_stderr - ActiveRecord::Base.connection.stubs(:create_database).raises( - ActiveRecord::Tasks::DatabaseAlreadyExists - ) + with_stubbed_connection_establish_connection do + ActiveRecord::Base.connection.stub( + :create_database, + proc { raise ActiveRecord::Tasks::DatabaseAlreadyExists } + ) do + ActiveRecord::Tasks::DatabaseTasks.create @configuration + + assert_equal "Database 'my-app-db' already exists\n", $stderr.string + end + end + end - ActiveRecord::Tasks::DatabaseTasks.create @configuration + private - assert_equal "Database 'my-app-db' already exists\n", $stderr.string - end + def with_stubbed_connection_establish_connection + ActiveRecord::Base.stub(:establish_connection, nil) do + ActiveRecord::Base.stub(:connection, @connection) do + yield + end + end + end end class MysqlDBCreateWithInvalidPermissionsTest < ActiveRecord::TestCase def setup - @connection = stub("Connection", create_database: true) @error = Mysql2::Error.new("Invalid permissions") @configuration = { "adapter" => "mysql2", @@ -85,10 +108,6 @@ if current_adapter?(:Mysql2Adapter) "username" => "pat", "password" => "wossname" } - - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection).raises(@error) - $stdout, @original_stdout = StringIO.new, $stdout $stderr, @original_stderr = StringIO.new, $stderr end @@ -98,23 +117,21 @@ if current_adapter?(:Mysql2Adapter) end def test_raises_error - assert_raises(Mysql2::Error) do - ActiveRecord::Tasks::DatabaseTasks.create @configuration + ActiveRecord::Base.stub(:establish_connection, -> * { raise @error }) do + assert_raises(Mysql2::Error, "Invalid permissions") do + ActiveRecord::Tasks::DatabaseTasks.create @configuration + end end end end class MySQLDBDropTest < ActiveRecord::TestCase def setup - @connection = stub(drop_database: true) + @connection = Class.new { def drop_database(name); end }.new @configuration = { "adapter" => "mysql2", "database" => "my-app-db" } - - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection).returns(true) - $stdout, @original_stdout = StringIO.new, $stdout $stderr, @original_stderr = StringIO.new, $stderr end @@ -124,91 +141,122 @@ if current_adapter?(:Mysql2Adapter) end def test_establishes_connection_to_mysql_database - ActiveRecord::Base.expects(:establish_connection).with @configuration + with_stubbed_connection_establish_connection do + ActiveRecord::Base.expects(:establish_connection).with @configuration - ActiveRecord::Tasks::DatabaseTasks.drop @configuration + ActiveRecord::Tasks::DatabaseTasks.drop @configuration + end end def test_drops_database - @connection.expects(:drop_database).with("my-app-db") - - ActiveRecord::Tasks::DatabaseTasks.drop @configuration + with_stubbed_connection_establish_connection do + assert_called_with(@connection, :drop_database, ["my-app-db"]) do + ActiveRecord::Tasks::DatabaseTasks.drop @configuration + end + end end def test_when_database_dropped_successfully_outputs_info_to_stdout - ActiveRecord::Tasks::DatabaseTasks.drop @configuration + with_stubbed_connection_establish_connection do + ActiveRecord::Tasks::DatabaseTasks.drop @configuration - assert_equal "Dropped database 'my-app-db'\n", $stdout.string + assert_equal "Dropped database 'my-app-db'\n", $stdout.string + end end + + private + + def with_stubbed_connection_establish_connection + ActiveRecord::Base.stub(:establish_connection, nil) do + ActiveRecord::Base.stub(:connection, @connection) do + yield + end + end + end end class MySQLPurgeTest < ActiveRecord::TestCase def setup - @connection = stub(recreate_database: true) + @connection = Class.new { def recreate_database(*); end }.new @configuration = { "adapter" => "mysql2", "database" => "test-db" } - - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection).returns(true) end def test_establishes_connection_to_the_appropriate_database - ActiveRecord::Base.expects(:establish_connection).with(@configuration) + with_stubbed_connection_establish_connection do + ActiveRecord::Base.expects(:establish_connection).with(@configuration) - ActiveRecord::Tasks::DatabaseTasks.purge @configuration + ActiveRecord::Tasks::DatabaseTasks.purge @configuration + end end def test_recreates_database_with_no_default_options - @connection.expects(:recreate_database). - with("test-db", {}) - - ActiveRecord::Tasks::DatabaseTasks.purge @configuration + with_stubbed_connection_establish_connection do + assert_called_with(@connection, :recreate_database, ["test-db", {}]) do + ActiveRecord::Tasks::DatabaseTasks.purge @configuration + end + end end def test_recreates_database_with_the_given_options - @connection.expects(:recreate_database). - with("test-db", charset: "latin", collation: "latin1_swedish_ci") - - ActiveRecord::Tasks::DatabaseTasks.purge @configuration.merge( - "encoding" => "latin", "collation" => "latin1_swedish_ci") + with_stubbed_connection_establish_connection do + assert_called_with( + @connection, + :recreate_database, + ["test-db", charset: "latin", collation: "latin1_swedish_ci"] + ) do + ActiveRecord::Tasks::DatabaseTasks.purge @configuration.merge( + "encoding" => "latin", "collation" => "latin1_swedish_ci") + end + end end + + private + + def with_stubbed_connection_establish_connection + ActiveRecord::Base.stub(:establish_connection, nil) do + ActiveRecord::Base.stub(:connection, @connection) do + yield + end + end + end end class MysqlDBCharsetTest < ActiveRecord::TestCase def setup - @connection = stub(create_database: true) + @connection = Class.new { def charset; end }.new @configuration = { "adapter" => "mysql2", "database" => "my-app-db" } - - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection).returns(true) end def test_db_retrieves_charset - @connection.expects(:charset) - ActiveRecord::Tasks::DatabaseTasks.charset @configuration + ActiveRecord::Base.stub(:connection, @connection) do + assert_called(@connection, :charset) do + ActiveRecord::Tasks::DatabaseTasks.charset @configuration + end + end end end class MysqlDBCollationTest < ActiveRecord::TestCase def setup - @connection = stub(create_database: true) + @connection = Class.new { def collation; end }.new @configuration = { "adapter" => "mysql2", "database" => "my-app-db" } - - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection).returns(true) end def test_db_retrieves_collation - @connection.expects(:collation) - ActiveRecord::Tasks::DatabaseTasks.collation @configuration + ActiveRecord::Base.stub(:connection, @connection) do + assert_called_with(@connection, :collation) do + ActiveRecord::Tasks::DatabaseTasks.collation @configuration + end + end end end @@ -245,15 +293,15 @@ if current_adapter?(:Mysql2Adapter) def test_structure_dump_with_ignore_tables filename = "awesome-file.sql" - ActiveRecord::SchemaDumper.expects(:ignore_tables).returns(["foo", "bar"]) - - assert_called_with( - Kernel, - :system, - ["mysqldump", "--result-file", filename, "--no-data", "--routines", "--skip-comments", "--ignore-table=test-db.foo", "--ignore-table=test-db.bar", "test-db"], - returns: true - ) do - ActiveRecord::Tasks::DatabaseTasks.structure_dump(@configuration, filename) + ActiveRecord::SchemaDumper.stub(:ignore_tables, ["foo", "bar"]) do + assert_called_with( + Kernel, + :system, + ["mysqldump", "--result-file", filename, "--no-data", "--routines", "--skip-comments", "--ignore-table=test-db.foo", "--ignore-table=test-db.bar", "test-db"], + returns: true + ) do + ActiveRecord::Tasks::DatabaseTasks.structure_dump(@configuration, filename) + end end end diff --git a/activerecord/test/cases/tasks/postgresql_rake_test.rb b/activerecord/test/cases/tasks/postgresql_rake_test.rb index a1a3700f07..289847e514 100644 --- a/activerecord/test/cases/tasks/postgresql_rake_test.rb +++ b/activerecord/test/cases/tasks/postgresql_rake_test.rb @@ -7,15 +7,11 @@ if current_adapter?(:PostgreSQLAdapter) module ActiveRecord class PostgreSQLDBCreateTest < ActiveRecord::TestCase def setup - @connection = stub(create_database: true) + @connection = Class.new { def create_database(*); end }.new @configuration = { "adapter" => "postgresql", "database" => "my-app-db" } - - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection).returns(true) - $stdout, @original_stdout = StringIO.new, $stdout $stderr, @original_stderr = StringIO.new, $stderr end @@ -25,82 +21,119 @@ if current_adapter?(:PostgreSQLAdapter) end def test_establishes_connection_to_postgresql_database - ActiveRecord::Base.expects(:establish_connection).with( - "adapter" => "postgresql", - "database" => "postgres", - "schema_search_path" => "public" - ) - - ActiveRecord::Tasks::DatabaseTasks.create @configuration + ActiveRecord::Base.stubs(:establish_connection) + ActiveRecord::Base.stub(:connection, @connection) do + ActiveRecord::Base.expects(:establish_connection).with( + "adapter" => "postgresql", + "database" => "postgres", + "schema_search_path" => "public" + ) + ActiveRecord::Tasks::DatabaseTasks.create @configuration + end end def test_creates_database_with_default_encoding - @connection.expects(:create_database). - with("my-app-db", @configuration.merge("encoding" => "utf8")) - - ActiveRecord::Tasks::DatabaseTasks.create @configuration + with_stubbed_connection_establish_connection do + assert_called_with( + @connection, + :create_database, + ["my-app-db", @configuration.merge("encoding" => "utf8")] + ) do + ActiveRecord::Tasks::DatabaseTasks.create @configuration + end + end end def test_creates_database_with_given_encoding - @connection.expects(:create_database). - with("my-app-db", @configuration.merge("encoding" => "latin")) - - ActiveRecord::Tasks::DatabaseTasks.create @configuration. - merge("encoding" => "latin") + with_stubbed_connection_establish_connection do + assert_called_with( + @connection, + :create_database, + ["my-app-db", @configuration.merge("encoding" => "latin")] + ) do + ActiveRecord::Tasks::DatabaseTasks.create @configuration. + merge("encoding" => "latin") + end + end end def test_creates_database_with_given_collation_and_ctype - @connection.expects(:create_database). - with("my-app-db", @configuration.merge("encoding" => "utf8", "collation" => "ja_JP.UTF8", "ctype" => "ja_JP.UTF8")) - - ActiveRecord::Tasks::DatabaseTasks.create @configuration. - merge("collation" => "ja_JP.UTF8", "ctype" => "ja_JP.UTF8") + with_stubbed_connection_establish_connection do + assert_called_with( + @connection, + :create_database, + [ + "my-app-db", + @configuration.merge( + "encoding" => "utf8", + "collation" => "ja_JP.UTF8", + "ctype" => "ja_JP.UTF8" + ) + ] + ) do + ActiveRecord::Tasks::DatabaseTasks.create @configuration. + merge("collation" => "ja_JP.UTF8", "ctype" => "ja_JP.UTF8") + end + end end def test_establishes_connection_to_new_database - ActiveRecord::Base.expects(:establish_connection).with(@configuration) + ActiveRecord::Base.stubs(:establish_connection) + ActiveRecord::Base.stub(:connection, @connection) do + ActiveRecord::Base.expects(:establish_connection).with(@configuration) - ActiveRecord::Tasks::DatabaseTasks.create @configuration + ActiveRecord::Tasks::DatabaseTasks.create @configuration + end end def test_db_create_with_error_prints_message - ActiveRecord::Base.stubs(:establish_connection).raises(Exception) - - $stderr.stubs(:puts).returns(true) - $stderr.expects(:puts). - with("Couldn't create database for #{@configuration.inspect}") - - assert_raises(Exception) { ActiveRecord::Tasks::DatabaseTasks.create @configuration } + ActiveRecord::Base.stub(:connection, @connection) do + ActiveRecord::Base.stub(:establish_connection, -> * { raise Exception }) do + assert_raises(Exception) { ActiveRecord::Tasks::DatabaseTasks.create @configuration } + assert_match "Couldn't create database for #{@configuration.inspect}", $stderr.string + end + end end def test_when_database_created_successfully_outputs_info_to_stdout - ActiveRecord::Tasks::DatabaseTasks.create @configuration + with_stubbed_connection_establish_connection do + ActiveRecord::Tasks::DatabaseTasks.create @configuration - assert_equal "Created database 'my-app-db'\n", $stdout.string + assert_equal "Created database 'my-app-db'\n", $stdout.string + end end def test_create_when_database_exists_outputs_info_to_stderr - ActiveRecord::Base.connection.stubs(:create_database).raises( - ActiveRecord::Tasks::DatabaseAlreadyExists - ) - - ActiveRecord::Tasks::DatabaseTasks.create @configuration + with_stubbed_connection_establish_connection do + ActiveRecord::Base.connection.stub( + :create_database, + proc { raise ActiveRecord::Tasks::DatabaseAlreadyExists } + ) do + ActiveRecord::Tasks::DatabaseTasks.create @configuration - assert_equal "Database 'my-app-db' already exists\n", $stderr.string + assert_equal "Database 'my-app-db' already exists\n", $stderr.string + end + end end + + private + + def with_stubbed_connection_establish_connection + ActiveRecord::Base.stub(:connection, @connection) do + ActiveRecord::Base.stub(:establish_connection, nil) do + yield + end + end + end end class PostgreSQLDBDropTest < ActiveRecord::TestCase def setup - @connection = stub(drop_database: true) + @connection = Class.new { def drop_database(*); end }.new @configuration = { "adapter" => "postgresql", "database" => "my-app-db" } - - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection).returns(true) - $stdout, @original_stdout = StringIO.new, $stdout $stderr, @original_stderr = StringIO.new, $stderr end @@ -110,125 +143,171 @@ if current_adapter?(:PostgreSQLAdapter) end def test_establishes_connection_to_postgresql_database - ActiveRecord::Base.expects(:establish_connection).with( - "adapter" => "postgresql", - "database" => "postgres", - "schema_search_path" => "public" - ) - - ActiveRecord::Tasks::DatabaseTasks.drop @configuration + ActiveRecord::Base.stub(:connection, @connection) do + ActiveRecord::Base.expects(:establish_connection).with( + "adapter" => "postgresql", + "database" => "postgres", + "schema_search_path" => "public" + ) + ActiveRecord::Tasks::DatabaseTasks.drop @configuration + end end def test_drops_database - @connection.expects(:drop_database).with("my-app-db") - - ActiveRecord::Tasks::DatabaseTasks.drop @configuration + with_stubbed_connection_establish_connection do + assert_called_with( + @connection, + :drop_database, + ["my-app-db"] + ) do + ActiveRecord::Tasks::DatabaseTasks.drop @configuration + end + end end def test_when_database_dropped_successfully_outputs_info_to_stdout - ActiveRecord::Tasks::DatabaseTasks.drop @configuration + with_stubbed_connection_establish_connection do + ActiveRecord::Tasks::DatabaseTasks.drop @configuration - assert_equal "Dropped database 'my-app-db'\n", $stdout.string + assert_equal "Dropped database 'my-app-db'\n", $stdout.string + end end + + private + + def with_stubbed_connection_establish_connection + ActiveRecord::Base.stub(:connection, @connection) do + ActiveRecord::Base.stub(:establish_connection, nil) do + yield + end + end + end end class PostgreSQLPurgeTest < ActiveRecord::TestCase def setup - @connection = stub(create_database: true, drop_database: true) + @connection = Class.new do + def create_database(*); end + def drop_database(*); end + end.new @configuration = { "adapter" => "postgresql", "database" => "my-app-db" } - - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:clear_active_connections!).returns(true) - ActiveRecord::Base.stubs(:establish_connection).returns(true) end def test_clears_active_connections - ActiveRecord::Base.expects(:clear_active_connections!) - - ActiveRecord::Tasks::DatabaseTasks.purge @configuration + with_stubbed_connection do + ActiveRecord::Base.stub(:establish_connection, nil) do + assert_called(ActiveRecord::Base, :clear_active_connections!) do + ActiveRecord::Tasks::DatabaseTasks.purge @configuration + end + end + end end def test_establishes_connection_to_postgresql_database - ActiveRecord::Base.expects(:establish_connection).with( - "adapter" => "postgresql", - "database" => "postgres", - "schema_search_path" => "public" - ) - - ActiveRecord::Tasks::DatabaseTasks.purge @configuration + ActiveRecord::Base.stubs(:establish_connection) + with_stubbed_connection do + ActiveRecord::Base.expects(:establish_connection).with( + "adapter" => "postgresql", + "database" => "postgres", + "schema_search_path" => "public" + ) + + ActiveRecord::Tasks::DatabaseTasks.purge @configuration + end end def test_drops_database - @connection.expects(:drop_database).with("my-app-db") - - ActiveRecord::Tasks::DatabaseTasks.purge @configuration + with_stubbed_connection do + ActiveRecord::Base.stub(:establish_connection, nil) do + assert_called_with(@connection, :drop_database, ["my-app-db"]) do + ActiveRecord::Tasks::DatabaseTasks.purge @configuration + end + end + end end def test_creates_database - @connection.expects(:create_database). - with("my-app-db", @configuration.merge("encoding" => "utf8")) - - ActiveRecord::Tasks::DatabaseTasks.purge @configuration + with_stubbed_connection do + ActiveRecord::Base.stub(:establish_connection, nil) do + assert_called_with( + @connection, + :create_database, + ["my-app-db", @configuration.merge("encoding" => "utf8")] + ) do + ActiveRecord::Tasks::DatabaseTasks.purge @configuration + end + end + end end def test_establishes_connection - ActiveRecord::Base.expects(:establish_connection).with(@configuration) + ActiveRecord::Base.stubs(:establish_connection) + with_stubbed_connection do + ActiveRecord::Base.expects(:establish_connection).with(@configuration) - ActiveRecord::Tasks::DatabaseTasks.purge @configuration + ActiveRecord::Tasks::DatabaseTasks.purge @configuration + end end + + private + + def with_stubbed_connection + ActiveRecord::Base.stub(:connection, @connection) do + yield + end + end end class PostgreSQLDBCharsetTest < ActiveRecord::TestCase def setup - @connection = stub(create_database: true) + @connection = Class.new do + def create_database(*); end + def encoding; end + end.new @configuration = { "adapter" => "postgresql", "database" => "my-app-db" } - - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection).returns(true) end def test_db_retrieves_charset - @connection.expects(:encoding) - ActiveRecord::Tasks::DatabaseTasks.charset @configuration + ActiveRecord::Base.stub(:connection, @connection) do + assert_called(@connection, :encoding) do + ActiveRecord::Tasks::DatabaseTasks.charset @configuration + end + end end end class PostgreSQLDBCollationTest < ActiveRecord::TestCase def setup - @connection = stub(create_database: true) + @connection = Class.new { def collation; end }.new @configuration = { "adapter" => "postgresql", "database" => "my-app-db" } - - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection).returns(true) end def test_db_retrieves_collation - @connection.expects(:collation) - ActiveRecord::Tasks::DatabaseTasks.collation @configuration + ActiveRecord::Base.stub(:connection, @connection) do + assert_called(@connection, :collation) do + ActiveRecord::Tasks::DatabaseTasks.collation @configuration + end + end end end class PostgreSQLStructureDumpTest < ActiveRecord::TestCase def setup - @connection = stub(schema_search_path: nil, structure_dump: true) @configuration = { "adapter" => "postgresql", "database" => "my-app-db" } @filename = "/tmp/awesome-file.sql" FileUtils.touch(@filename) - - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection).returns(true) end def teardown @@ -247,12 +326,12 @@ if current_adapter?(:PostgreSQLAdapter) end def test_structure_dump_header_comments_removed - Kernel.stubs(:system).returns(true) - File.write(@filename, "-- header comment\n\n-- more header comment\n statement \n-- lower comment\n") - - ActiveRecord::Tasks::DatabaseTasks.structure_dump(@configuration, @filename) + Kernel.stub(:system, true) do + File.write(@filename, "-- header comment\n\n-- more header comment\n statement \n-- lower comment\n") + ActiveRecord::Tasks::DatabaseTasks.structure_dump(@configuration, @filename) - assert_equal [" statement \n", "-- lower comment\n"], File.readlines(@filename).first(2) + assert_equal [" statement \n", "-- lower comment\n"], File.readlines(@filename).first(2) + end end def test_structure_dump_with_extra_flags @@ -358,14 +437,10 @@ if current_adapter?(:PostgreSQLAdapter) class PostgreSQLStructureLoadTest < ActiveRecord::TestCase def setup - @connection = stub @configuration = { "adapter" => "postgresql", "database" => "my-app-db" } - - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection).returns(true) end def test_structure_load diff --git a/activerecord/test/cases/tasks/sqlite_rake_test.rb b/activerecord/test/cases/tasks/sqlite_rake_test.rb index d368a7a6ee..7eb062b456 100644 --- a/activerecord/test/cases/tasks/sqlite_rake_test.rb +++ b/activerecord/test/cases/tasks/sqlite_rake_test.rb @@ -9,16 +9,10 @@ if current_adapter?(:SQLite3Adapter) class SqliteDBCreateTest < ActiveRecord::TestCase def setup @database = "db_create.sqlite3" - @connection = stub :connection @configuration = { "adapter" => "sqlite3", "database" => @database } - - File.stubs(:exist?).returns(false) - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection).returns(true) - $stdout, @original_stdout = StringIO.new, $stdout $stderr, @original_stderr = StringIO.new, $stderr end @@ -28,63 +22,62 @@ if current_adapter?(:SQLite3Adapter) end def test_db_checks_database_exists - File.expects(:exist?).with(@database).returns(false) - - ActiveRecord::Tasks::DatabaseTasks.create @configuration, "/rails/root" + ActiveRecord::Base.stub(:establish_connection, nil) do + assert_called_with(File, :exist?, [@database], returns: false) do + ActiveRecord::Tasks::DatabaseTasks.create @configuration, "/rails/root" + end + end end def test_when_db_created_successfully_outputs_info_to_stdout - ActiveRecord::Tasks::DatabaseTasks.create @configuration, "/rails/root" + ActiveRecord::Base.stub(:establish_connection, nil) do + ActiveRecord::Tasks::DatabaseTasks.create @configuration, "/rails/root" - assert_equal "Created database '#{@database}'\n", $stdout.string + assert_equal "Created database '#{@database}'\n", $stdout.string + end end def test_db_create_when_file_exists - File.stubs(:exist?).returns(true) - - ActiveRecord::Tasks::DatabaseTasks.create @configuration, "/rails/root" + File.stub(:exist?, true) do + ActiveRecord::Tasks::DatabaseTasks.create @configuration, "/rails/root" - assert_equal "Database '#{@database}' already exists\n", $stderr.string + assert_equal "Database '#{@database}' already exists\n", $stderr.string + end end def test_db_create_with_file_does_nothing - File.stubs(:exist?).returns(true) - $stderr.stubs(:puts).returns(nil) + File.stub(:exist?, true) do + ActiveRecord::Base.expects(:establish_connection).never - ActiveRecord::Base.expects(:establish_connection).never - - ActiveRecord::Tasks::DatabaseTasks.create @configuration, "/rails/root" + ActiveRecord::Tasks::DatabaseTasks.create @configuration, "/rails/root" + end end def test_db_create_establishes_a_connection - ActiveRecord::Base.expects(:establish_connection).with(@configuration) - - ActiveRecord::Tasks::DatabaseTasks.create @configuration, "/rails/root" + assert_called_with(ActiveRecord::Base, :establish_connection, [@configuration]) do + ActiveRecord::Tasks::DatabaseTasks.create @configuration, "/rails/root" + end end def test_db_create_with_error_prints_message - ActiveRecord::Base.stubs(:establish_connection).raises(Exception) - - $stderr.stubs(:puts).returns(true) - $stderr.expects(:puts). - with("Couldn't create database for #{@configuration.inspect}") - - assert_raises(Exception) { ActiveRecord::Tasks::DatabaseTasks.create @configuration, "/rails/root" } + ActiveRecord::Base.stub(:establish_connection, proc { raise Exception }) do + assert_raises(Exception) { ActiveRecord::Tasks::DatabaseTasks.create @configuration, "/rails/root" } + assert_match "Couldn't create database for #{@configuration.inspect}", $stderr.string + end end end class SqliteDBDropTest < ActiveRecord::TestCase def setup @database = "db_create.sqlite3" - @path = stub(to_s: "/absolute/path", absolute?: true) @configuration = { "adapter" => "sqlite3", "database" => @database } - - Pathname.stubs(:new).returns(@path) - File.stubs(:join).returns("/former/relative/path") - FileUtils.stubs(:rm).returns(true) + @path = Class.new do + def to_s; "/absolute/path" end + def absolute?; true end + end.new $stdout, @original_stdout = StringIO.new, $stdout $stderr, @original_stderr = StringIO.new, $stderr @@ -95,77 +88,76 @@ if current_adapter?(:SQLite3Adapter) end def test_creates_path_from_database - Pathname.expects(:new).with(@database).returns(@path) - - ActiveRecord::Tasks::DatabaseTasks.drop @configuration, "/rails/root" + assert_called_with(Pathname, :new, [@database], returns: @path) do + ActiveRecord::Tasks::DatabaseTasks.drop @configuration, "/rails/root" + end end def test_removes_file_with_absolute_path - File.stubs(:exist?).returns(true) - @path.stubs(:absolute?).returns(true) - - FileUtils.expects(:rm).with("/absolute/path") - - ActiveRecord::Tasks::DatabaseTasks.drop @configuration, "/rails/root" + Pathname.stub(:new, @path) do + assert_called_with(FileUtils, :rm, ["/absolute/path"]) do + ActiveRecord::Tasks::DatabaseTasks.drop @configuration, "/rails/root" + end + end end def test_generates_absolute_path_with_given_root - @path.stubs(:absolute?).returns(false) - - File.expects(:join).with("/rails/root", @path). - returns("/former/relative/path") - - ActiveRecord::Tasks::DatabaseTasks.drop @configuration, "/rails/root" + Pathname.stub(:new, @path) do + @path.stub(:absolute?, false) do + assert_called_with(File, :join, ["/rails/root", @path], + returns: "/former/relative/path" + ) do + ActiveRecord::Tasks::DatabaseTasks.drop @configuration, "/rails/root" + end + end + end end def test_removes_file_with_relative_path - File.stubs(:exist?).returns(true) - @path.stubs(:absolute?).returns(false) - - FileUtils.expects(:rm).with("/former/relative/path") - - ActiveRecord::Tasks::DatabaseTasks.drop @configuration, "/rails/root" + File.stub(:join, "/former/relative/path") do + @path.stub(:absolute?, false) do + assert_called_with(FileUtils, :rm, ["/former/relative/path"]) do + ActiveRecord::Tasks::DatabaseTasks.drop @configuration, "/rails/root" + end + end + end end def test_when_db_dropped_successfully_outputs_info_to_stdout - ActiveRecord::Tasks::DatabaseTasks.drop @configuration, "/rails/root" + FileUtils.stub(:rm, nil) do + ActiveRecord::Tasks::DatabaseTasks.drop @configuration, "/rails/root" - assert_equal "Dropped database '#{@database}'\n", $stdout.string + assert_equal "Dropped database '#{@database}'\n", $stdout.string + end end end class SqliteDBCharsetTest < ActiveRecord::TestCase def setup @database = "db_create.sqlite3" - @connection = stub :connection + @connection = Class.new { def encoding; end }.new @configuration = { "adapter" => "sqlite3", "database" => @database } - - File.stubs(:exist?).returns(false) - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection).returns(true) end def test_db_retrieves_charset - @connection.expects(:encoding) - ActiveRecord::Tasks::DatabaseTasks.charset @configuration, "/rails/root" + ActiveRecord::Base.stub(:connection, @connection) do + assert_called(@connection, :encoding) do + ActiveRecord::Tasks::DatabaseTasks.charset @configuration, "/rails/root" + end + end end end class SqliteDBCollationTest < ActiveRecord::TestCase def setup @database = "db_create.sqlite3" - @connection = stub :connection @configuration = { "adapter" => "sqlite3", "database" => @database } - - File.stubs(:exist?).returns(false) - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection).returns(true) end def test_db_retrieves_collation diff --git a/activerecord/test/cases/transaction_callbacks_test.rb b/activerecord/test/cases/transaction_callbacks_test.rb index 05941c75ac..c0be45eee7 100644 --- a/activerecord/test/cases/transaction_callbacks_test.rb +++ b/activerecord/test/cases/transaction_callbacks_test.rb @@ -139,6 +139,23 @@ class TransactionCallbacksTest < ActiveRecord::TestCase assert_equal [], reply.history end + def test_only_call_after_commit_on_destroy_after_transaction_commits_for_destroyed_new_record + new_record = TopicWithCallbacks.new(title: "New topic", written_on: Date.today) + add_transaction_execution_blocks new_record + + new_record.destroy + assert_equal [:commit_on_destroy], new_record.history + end + + def test_save_in_after_create_commit_wont_invoke_extra_after_create_commit + new_record = TopicWithCallbacks.new(title: "New topic", written_on: Date.today) + add_transaction_execution_blocks new_record + new_record.after_commit_block(:create) { |r| r.save! } + + new_record.save! + assert_equal [:commit_on_create, :commit_on_update], new_record.history + end + def test_only_call_after_commit_on_create_and_doesnt_leaky r = ReplyWithCallbacks.new(content: "foo") r.save_on_after_create = true diff --git a/activerecord/test/cases/transactions_test.rb b/activerecord/test/cases/transactions_test.rb index 5b685ca564..46463ac414 100644 --- a/activerecord/test/cases/transactions_test.rb +++ b/activerecord/test/cases/transactions_test.rb @@ -573,7 +573,6 @@ class TransactionTest < ActiveRecord::TestCase assert_called(Topic.connection, :begin_db_transaction) do Topic.connection.stub(:commit_db_transaction, -> { raise("OH NOES") }) do assert_called(Topic.connection, :rollback_db_transaction) do - e = assert_raise RuntimeError do Topic.transaction do # do nothing diff --git a/activerecord/test/fixtures/memberships.yml b/activerecord/test/fixtures/memberships.yml index a5d52bd438..f7ca227533 100644 --- a/activerecord/test/fixtures/memberships.yml +++ b/activerecord/test/fixtures/memberships.yml @@ -26,6 +26,13 @@ blarpy_winkup_crazy_club: favourite: false type: CurrentMembership +super_membership_of_boring_club: + joined_on: <%= 3.weeks.ago.to_s(:db) %> + club: boring_club + member_id: 1 + favourite: false + type: SuperMembership + selected_membership_of_boring_club: joined_on: <%= 3.weeks.ago.to_s(:db) %> club: boring_club diff --git a/activerecord/test/models/admin/user.rb b/activerecord/test/models/admin/user.rb index 3f55364510..691f9f11be 100644 --- a/activerecord/test/models/admin/user.rb +++ b/activerecord/test/models/admin/user.rb @@ -22,6 +22,9 @@ class Admin::User < ActiveRecord::Base store :parent, accessors: [:birthday, :name], prefix: true store :spouse, accessors: [:birthday], prefix: :partner store_accessor :spouse, :name, prefix: :partner + store :configs, accessors: [ :secret_question ] + store :configs, accessors: [ :two_factor_auth ], suffix: true + store_accessor :configs, :login_retry, suffix: :config store :preferences, accessors: [ :remember_login ] store :json_data, accessors: [ :height, :weight ], coder: Coder.new store :json_data_empty, accessors: [ :is_a_good_guy ], coder: Coder.new diff --git a/activerecord/test/models/car.rb b/activerecord/test/models/car.rb index 3d6a7a96c2..8614926626 100644 --- a/activerecord/test/models/car.rb +++ b/activerecord/test/models/car.rb @@ -20,6 +20,8 @@ class Car < ActiveRecord::Base scope :incl_engines, -> { includes(:engines) } scope :order_using_new_style, -> { order("name asc") } + + attribute :wheels_owned_at, :datetime, default: -> { Time.now } end class CoolCar < Car diff --git a/activerecord/test/models/company.rb b/activerecord/test/models/company.rb index 6219f57fa1..d4d5275b78 100644 --- a/activerecord/test/models/company.rb +++ b/activerecord/test/models/company.rb @@ -150,6 +150,16 @@ class Client < Company throw :abort if throw_on_save end + attr_accessor :rollback_on_save + after_save do + raise ActiveRecord::Rollback if rollback_on_save + end + + attr_accessor :rollback_on_create_called + after_rollback(on: :create) do |client| + client.rollback_on_create_called = true + end + class RaisedOnDestroy < RuntimeError; end attr_accessor :raise_on_destroy before_destroy do diff --git a/activerecord/test/models/member.rb b/activerecord/test/models/member.rb index 4315ba1941..6e33ac0a6d 100644 --- a/activerecord/test/models/member.rb +++ b/activerecord/test/models/member.rb @@ -26,13 +26,14 @@ class Member < ActiveRecord::Base has_one :club_category, through: :club, source: :category has_one :general_club, -> { general }, through: :current_membership, source: :club - has_many :current_memberships, -> { where favourite: true } - has_many :clubs, through: :current_memberships + has_many :super_memberships + has_many :favourite_memberships, -> { where(favourite: true) }, class_name: "Membership" + has_many :clubs, through: :favourite_memberships has_many :tenant_memberships has_many :tenant_clubs, through: :tenant_memberships, class_name: "Club", source: :club - has_one :club_through_many, through: :current_memberships, source: :club + has_one :club_through_many, through: :favourite_memberships, source: :club belongs_to :admittable, polymorphic: true has_one :premium_club, through: :admittable diff --git a/activerecord/test/models/post.rb b/activerecord/test/models/post.rb index 54eb5e6783..640cdb33b4 100644 --- a/activerecord/test/models/post.rb +++ b/activerecord/test/models/post.rb @@ -253,6 +253,7 @@ class SpecialPostWithDefaultScope < ActiveRecord::Base self.inheritance_column = :disabled self.table_name = "posts" default_scope { where(id: [1, 5, 6]) } + scope :unscoped_all, -> { unscoped { all } } end class PostThatLoadsCommentsInAnAfterSaveHook < ActiveRecord::Base diff --git a/activerecord/test/models/reply.rb b/activerecord/test/models/reply.rb index bc829ec67f..0ea110f4f8 100644 --- a/activerecord/test/models/reply.rb +++ b/activerecord/test/models/reply.rb @@ -4,8 +4,9 @@ require "models/topic" class Reply < Topic belongs_to :topic, foreign_key: "parent_id", counter_cache: true - belongs_to :topic_with_primary_key, class_name: "Topic", primary_key: "title", foreign_key: "parent_title", counter_cache: "replies_count" + belongs_to :topic_with_primary_key, class_name: "Topic", primary_key: "title", foreign_key: "parent_title", counter_cache: "replies_count", touch: true has_many :replies, class_name: "SillyReply", dependent: :destroy, foreign_key: "parent_id" + has_many :silly_unique_replies, dependent: :destroy, foreign_key: "parent_id" end class UniqueReply < Reply @@ -14,6 +15,7 @@ class UniqueReply < Reply end class SillyUniqueReply < UniqueReply + validates :content, uniqueness: true end class WrongReply < Reply diff --git a/activerecord/test/models/topic.rb b/activerecord/test/models/topic.rb index 2e386d7669..72699046f9 100644 --- a/activerecord/test/models/topic.rb +++ b/activerecord/test/models/topic.rb @@ -81,6 +81,16 @@ class Topic < ActiveRecord::Base self.class.after_initialize_called = true end + attr_accessor :after_touch_called + + after_initialize do + self.after_touch_called = 0 + end + + after_touch do + self.after_touch_called += 1 + end + def approved=(val) @custom_approved = val write_attribute(:approved, val) diff --git a/activerecord/test/models/wheel.rb b/activerecord/test/models/wheel.rb index 8db57d181e..22fc74995f 100644 --- a/activerecord/test/models/wheel.rb +++ b/activerecord/test/models/wheel.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true class Wheel < ActiveRecord::Base - belongs_to :wheelable, polymorphic: true, counter_cache: true, touch: true + belongs_to :wheelable, polymorphic: true, counter_cache: true, touch: :wheels_owned_at end diff --git a/activerecord/test/schema/mysql2_specific_schema.rb b/activerecord/test/schema/mysql2_specific_schema.rb index e634e9e6b1..8371ba9528 100644 --- a/activerecord/test/schema/mysql2_specific_schema.rb +++ b/activerecord/test/schema/mysql2_specific_schema.rb @@ -1,16 +1,17 @@ # frozen_string_literal: true ActiveRecord::Schema.define do - - if ActiveRecord::Base.connection.version >= "5.6.0" + if subsecond_precision_supported? create_table :datetime_defaults, force: true do |t| t.datetime :modified_datetime, default: -> { "CURRENT_TIMESTAMP" } + t.datetime :precise_datetime, precision: 6, default: -> { "CURRENT_TIMESTAMP(6)" } end - end - create_table :timestamp_defaults, force: true do |t| - t.timestamp :nullable_timestamp - t.timestamp :modified_timestamp, default: -> { "CURRENT_TIMESTAMP" } + create_table :timestamp_defaults, force: true do |t| + t.timestamp :nullable_timestamp + t.timestamp :modified_timestamp, default: -> { "CURRENT_TIMESTAMP" } + t.timestamp :precise_timestamp, precision: 6, default: -> { "CURRENT_TIMESTAMP(6)" } + end end create_table :binary_fields, force: true do |t| diff --git a/activerecord/test/schema/oracle_specific_schema.rb b/activerecord/test/schema/oracle_specific_schema.rb index e236571caa..bc1e45ca80 100644 --- a/activerecord/test/schema/oracle_specific_schema.rb +++ b/activerecord/test/schema/oracle_specific_schema.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true ActiveRecord::Schema.define do - execute "drop table test_oracle_defaults" rescue nil execute "drop sequence test_oracle_defaults_seq" rescue nil execute "drop sequence companies_nonstd_seq" rescue nil @@ -38,5 +37,4 @@ create sequence test_oracle_defaults_seq minvalue 10000 ) SQL execute "create sequence defaults_seq minvalue 10000" - end diff --git a/activerecord/test/schema/postgresql_specific_schema.rb b/activerecord/test/schema/postgresql_specific_schema.rb index f15178d695..975824ed51 100644 --- a/activerecord/test/schema/postgresql_specific_schema.rb +++ b/activerecord/test/schema/postgresql_specific_schema.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true ActiveRecord::Schema.define do - enable_extension!("uuid-ossp", ActiveRecord::Base.connection) enable_extension!("pgcrypto", ActiveRecord::Base.connection) if ActiveRecord::Base.connection.supports_pgcrypto_uuid? diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb index 92ad25ef76..266e55f682 100644 --- a/activerecord/test/schema/schema.rb +++ b/activerecord/test/schema/schema.rb @@ -23,6 +23,7 @@ ActiveRecord::Schema.define do t.string :settings, null: true, limit: 1024 t.string :parent, null: true, limit: 1024 t.string :spouse, null: true, limit: 1024 + t.string :configs, null: true, limit: 1024 # MySQL does not allow default values for blobs. Fake it out with a # big varchar below. t.string :preferences, null: true, default: "", limit: 1024 @@ -35,6 +36,7 @@ ActiveRecord::Schema.define do create_table :aircraft, force: true do |t| t.string :name t.integer :wheels_count, default: 0, null: false + t.datetime :wheels_owned_at end create_table :articles, force: true do |t| @@ -125,7 +127,8 @@ ActiveRecord::Schema.define do create_table :cars, force: true do |t| t.string :name t.integer :engines_count - t.integer :wheels_count, default: 0 + t.integer :wheels_count, default: 0, null: false + t.datetime :wheels_owned_at t.column :lock_version, :integer, null: false, default: 0 t.timestamps null: false end diff --git a/activestorage/CHANGELOG.md b/activestorage/CHANGELOG.md index c8911fe611..0e9c2b5619 100644 --- a/activestorage/CHANGELOG.md +++ b/activestorage/CHANGELOG.md @@ -1,3 +1,22 @@ +* Uploaded files assigned to a record are persisted to storage when the record + is saved instead of immediately. + + In Rails 5.2, the following causes an uploaded file in `params[:avatar]` to + be stored: + + ```ruby + @user.avatar = params[:avatar] + ``` + + In Rails 6, the uploaded file is stored when `@user` is successfully saved. + + *George Claghorn* + +* Add the ability to reflect on defined attachments using the existing + ActiveRecord reflection mechanism. + + *Kevin Deisz* + * Variant arguments of `false` or `nil` will no longer be passed to the processor. For example, the following will not have the monochrome variation applied: diff --git a/activestorage/app/controllers/active_storage/blobs_controller.rb b/activestorage/app/controllers/active_storage/blobs_controller.rb index 92e54c386d..4fc3fbe824 100644 --- a/activestorage/app/controllers/active_storage/blobs_controller.rb +++ b/activestorage/app/controllers/active_storage/blobs_controller.rb @@ -8,7 +8,7 @@ class ActiveStorage::BlobsController < ActiveStorage::BaseController include ActiveStorage::SetBlob def show - expires_in ActiveStorage::Blob.service.url_expires_in + expires_in ActiveStorage.service_urls_expire_in redirect_to @blob.service_url(disposition: params[:disposition]) end end diff --git a/activestorage/app/controllers/active_storage/disk_controller.rb b/activestorage/app/controllers/active_storage/disk_controller.rb index 63918eb6f4..75cc11d6ff 100644 --- a/activestorage/app/controllers/active_storage/disk_controller.rb +++ b/activestorage/app/controllers/active_storage/disk_controller.rb @@ -5,30 +5,20 @@ # Always go through the BlobsController, or your own authenticated controller, rather than directly # to the service url. class ActiveStorage::DiskController < ActiveStorage::BaseController - include ActionController::Live - skip_forgery_protection def show if key = decode_verified_key - response.headers["Content-Type"] = params[:content_type] || DEFAULT_SEND_FILE_TYPE - response.headers["Content-Disposition"] = params[:disposition] || DEFAULT_SEND_FILE_DISPOSITION - - disk_service.download key do |chunk| - response.stream.write chunk - end + serve_file disk_service.path_for(key), content_type: params[:content_type], disposition: params[:disposition] else head :not_found end - ensure - response.stream.close end def update if token = decode_verified_token if acceptable_content?(token) disk_service.upload token[:key], request.body, checksum: token[:checksum] - head :no_content else head :unprocessable_entity end @@ -37,8 +27,6 @@ class ActiveStorage::DiskController < ActiveStorage::BaseController end rescue ActiveStorage::IntegrityError head :unprocessable_entity - ensure - response.stream.close end private @@ -51,6 +39,20 @@ class ActiveStorage::DiskController < ActiveStorage::BaseController ActiveStorage.verifier.verified(params[:encoded_key], purpose: :blob_key) end + def serve_file(path, content_type:, disposition:) + Rack::File.new(nil).serving(request, path).tap do |(status, headers, body)| + self.status = status + self.response_body = body + + headers.each do |name, value| + response.headers[name] = value + end + + response.headers["Content-Type"] = content_type || DEFAULT_SEND_FILE_TYPE + response.headers["Content-Disposition"] = disposition || DEFAULT_SEND_FILE_DISPOSITION + end + end + def decode_verified_token ActiveStorage.verifier.verified(params[:encoded_token], purpose: :blob_token) diff --git a/activestorage/app/controllers/active_storage/representations_controller.rb b/activestorage/app/controllers/active_storage/representations_controller.rb index ce9286db7d..98e11e5dbb 100644 --- a/activestorage/app/controllers/active_storage/representations_controller.rb +++ b/activestorage/app/controllers/active_storage/representations_controller.rb @@ -8,7 +8,7 @@ class ActiveStorage::RepresentationsController < ActiveStorage::BaseController include ActiveStorage::SetBlob def show - expires_in ActiveStorage::Blob.service.url_expires_in + expires_in ActiveStorage.service_urls_expire_in redirect_to @blob.representation(params[:variation_key]).processed.service_url(disposition: params[:disposition]) end end diff --git a/activestorage/app/jobs/active_storage/purge_job.rb b/activestorage/app/jobs/active_storage/purge_job.rb index 98874d2250..b021b5f2d0 100644 --- a/activestorage/app/jobs/active_storage/purge_job.rb +++ b/activestorage/app/jobs/active_storage/purge_job.rb @@ -2,8 +2,7 @@ # Provides asynchronous purging of ActiveStorage::Blob records via ActiveStorage::Blob#purge_later. class ActiveStorage::PurgeJob < ActiveStorage::BaseJob - # FIXME: Limit this to a custom ActiveStorage error - retry_on StandardError + discard_on ActiveRecord::RecordNotFound, ActiveRecord::InvalidForeignKey def perform(blob) blob.purge diff --git a/activestorage/app/models/active_storage/attachment.rb b/activestorage/app/models/active_storage/attachment.rb index c59877a9a5..1c4dc25094 100644 --- a/activestorage/app/models/active_storage/attachment.rb +++ b/activestorage/app/models/active_storage/attachment.rb @@ -15,17 +15,18 @@ class ActiveStorage::Attachment < ActiveRecord::Base delegate_missing_to :blob after_create_commit :analyze_blob_later, :identify_blob + after_destroy_commit :purge_dependent_blob_later - # Synchronously purges the blob (deletes it from the configured service) and destroys the attachment. + # Synchronously deletes the attachment and {purges the blob}[rdoc-ref:ActiveStorage::Blob#purge]. def purge + delete blob.purge - destroy end - # Destroys the attachment and asynchronously purges the blob (deletes it from the configured service). + # Deletes the attachment and {enqueues a background job}[rdoc-ref:ActiveStorage::Blob#purge_later] to purge the blob. def purge_later + delete blob.purge_later - destroy end private @@ -36,4 +37,13 @@ class ActiveStorage::Attachment < ActiveRecord::Base def analyze_blob_later blob.analyze_later unless blob.analyzed? end + + def purge_dependent_blob_later + blob.purge_later if dependent == :purge_later + end + + + def dependent + record.attachment_reflections[name]&.options[:dependent] + end end diff --git a/activestorage/app/models/active_storage/blob.rb b/activestorage/app/models/active_storage/blob.rb index 134d3bb2d9..bf87598a66 100644 --- a/activestorage/app/models/active_storage/blob.rb +++ b/activestorage/app/models/active_storage/blob.rb @@ -48,15 +48,17 @@ class ActiveStorage::Blob < ActiveRecord::Base # Returns a new, unsaved blob instance after the +io+ has been uploaded to the service. # When providing a content type, pass <tt>identify: false</tt> to bypass automatic content type inference. def build_after_upload(io:, filename:, content_type: nil, metadata: nil, identify: true) - new.tap do |blob| - blob.filename = filename - blob.content_type = content_type - blob.metadata = metadata - + new(filename: filename, content_type: content_type, metadata: metadata).tap do |blob| blob.upload(io, identify: identify) end end + def build_after_unfurling(io:, filename:, content_type: nil, metadata: nil, identify: true) #:nodoc: + new(filename: filename, content_type: content_type, metadata: metadata).tap do |blob| + blob.unfurl(io, identify: identify) + end + end + # Returns a saved blob instance after the +io+ has been uploaded to the service. Note, the blob is first built, # then the +io+ is uploaded, then the blob is saved. This is done this way to avoid uploading (which may take # time), while having an open database transaction. @@ -121,7 +123,7 @@ class ActiveStorage::Blob < ActiveRecord::Base # with users. Instead, the +service_url+ should only be exposed as a redirect from a stable, possibly authenticated URL. # Hiding the +service_url+ behind a redirect also gives you the power to change services without updating all URLs. And # it allows permanent URLs that redirect to the +service_url+ to be cached in the view. - def service_url(expires_in: service.url_expires_in, disposition: :inline, filename: nil, **options) + def service_url(expires_in: ActiveStorage.service_urls_expire_in, disposition: :inline, filename: nil, **options) filename = ActiveStorage::Filename.wrap(filename || self.filename) service.url key, expires_in: expires_in, filename: filename, content_type: content_type, @@ -130,7 +132,7 @@ class ActiveStorage::Blob < ActiveRecord::Base # Returns a URL that can be used to directly upload a file for this blob on the service. This URL is intended to be # short-lived for security and only generated on-demand by the client-side JavaScript responsible for doing the uploading. - def service_url_for_direct_upload(expires_in: service.url_expires_in) + def service_url_for_direct_upload(expires_in: ActiveStorage.service_urls_expire_in) service.url_for_direct_upload key, expires_in: expires_in, content_type: content_type, content_length: byte_size, checksum: checksum end @@ -152,12 +154,19 @@ class ActiveStorage::Blob < ActiveRecord::Base # Normally, you do not have to call this method directly at all. Use the factory class methods of +build_after_upload+ # and +create_after_upload!+. def upload(io, identify: true) + unfurl io, identify: identify + upload_without_unfurling io + end + + def unfurl(io, identify: true) #:nodoc: self.checksum = compute_checksum_in_chunks(io) self.content_type = extract_content_type(io) if content_type.nil? || identify self.byte_size = io.size self.identified = true + end - service.upload(key, io, checksum: checksum) + def upload_without_unfurling(io) #:nodoc: + service.upload key, io, checksum: checksum end # Downloads the file associated with this blob. If no block is given, the entire file is read into memory and returned. @@ -167,13 +176,25 @@ class ActiveStorage::Blob < ActiveRecord::Base end # 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) end - # Deletes the file on the service that's associated with this blob. This should only be done if the blob is going to be - # deleted as well or you will essentially have a dead reference. It's recommended to use the +#purge+ and +#purge_later+ + # Deletes the files on the service associated with the blob. This should only be done if the blob is going to be + # deleted as well or you will essentially have a dead reference. It's recommended to use #purge and #purge_later # methods in most circumstances. def delete service.delete(key) @@ -182,14 +203,14 @@ class ActiveStorage::Blob < ActiveRecord::Base # Deletes the file on the service and then destroys the blob record. This is the recommended way to dispose of unwanted # blobs. Note, though, that deleting the file off the service will initiate a HTTP connection to the service, which may - # be slow or prevented, so you should not use this method inside a transaction or in callbacks. Use +#purge_later+ instead. + # be slow or prevented, so you should not use this method inside a transaction or in callbacks. Use #purge_later instead. def purge - delete destroy + delete end - # Enqueues an ActiveStorage::PurgeJob job that'll call +purge+. This is the recommended way to purge blobs when the call - # needs to be made from a transaction, a callback, or any other real-time scenario. + # Enqueues an ActiveStorage::PurgeJob to call #purge. This is the recommended way to purge blobs from a transaction, + # an Active Record callback, or in any other real-time scenario. def purge_later ActiveStorage::PurgeJob.perform_later(self) end diff --git a/activestorage/app/models/active_storage/preview.rb b/activestorage/app/models/active_storage/preview.rb index de58763399..dd50494799 100644 --- a/activestorage/app/models/active_storage/preview.rb +++ b/activestorage/app/models/active_storage/preview.rb @@ -22,8 +22,8 @@ # Outside of a Rails application, modify +ActiveStorage.previewers+ instead. # # The built-in previewers rely on third-party system libraries. Specifically, the built-in video previewer requires -# {ffmpeg}[https://www.ffmpeg.org]. Two PDF previewers are provided: one requires {Poppler}[https://poppler.freedesktop.org], -# and the other requires {mupdf}[https://mupdf.com] (version 1.8 or newer). To preview PDFs, install either Poppler or mupdf. +# {FFmpeg}[https://www.ffmpeg.org]. Two PDF previewers are provided: one requires {Poppler}[https://poppler.freedesktop.org], +# and the other requires {muPDF}[https://mupdf.com] (version 1.8 or newer). To preview PDFs, install either Poppler or muPDF. # # These libraries are not provided by Rails. You must install them yourself to use the built-in previewers. Before you # install and use third-party software, make sure you understand the licensing implications of doing so. diff --git a/activestorage/app/models/active_storage/variant.rb b/activestorage/app/models/active_storage/variant.rb index 1df36e37d9..056fd2be99 100644 --- a/activestorage/app/models/active_storage/variant.rb +++ b/activestorage/app/models/active_storage/variant.rb @@ -79,7 +79,7 @@ class ActiveStorage::Variant # Use <tt>url_for(variant)</tt> (or the implied form, like +link_to variant+ or +redirect_to variant+) to get the stable URL # for a variant that points to the ActiveStorage::RepresentationsController, which in turn will use this +service_call+ method # for its redirection. - def service_url(expires_in: service.url_expires_in, disposition: :inline) + def service_url(expires_in: ActiveStorage.service_urls_expire_in, disposition: :inline) service.url key, expires_in: expires_in, disposition: disposition, filename: filename, content_type: content_type end diff --git a/activestorage/db/migrate/20170806125915_create_active_storage_tables.rb b/activestorage/db/migrate/20170806125915_create_active_storage_tables.rb index 9e31e3966a..cfaf01cd5e 100644 --- a/activestorage/db/migrate/20170806125915_create_active_storage_tables.rb +++ b/activestorage/db/migrate/20170806125915_create_active_storage_tables.rb @@ -20,6 +20,7 @@ class CreateActiveStorageTables < ActiveRecord::Migration[5.2] t.datetime :created_at, null: false t.index [ :record_type, :record_id, :name, :blob_id ], name: "index_active_storage_attachments_uniqueness", unique: true + t.foreign_key :active_storage_blobs, column: :blob_id end end end diff --git a/activestorage/lib/active_storage.rb b/activestorage/lib/active_storage.rb index e1deee1d82..928db32691 100644 --- a/activestorage/lib/active_storage.rb +++ b/activestorage/lib/active_storage.rb @@ -49,4 +49,5 @@ module ActiveStorage mattr_accessor :paths, default: {} mattr_accessor :variable_content_types, default: [] mattr_accessor :content_types_to_serve_as_binary, default: [] + mattr_accessor :service_urls_expire_in, default: 5.minutes end diff --git a/activestorage/lib/active_storage/analyzer/video_analyzer.rb b/activestorage/lib/active_storage/analyzer/video_analyzer.rb index e31bdb0edb..18d8ff8237 100644 --- a/activestorage/lib/active_storage/analyzer/video_analyzer.rb +++ b/activestorage/lib/active_storage/analyzer/video_analyzer.rb @@ -16,7 +16,7 @@ module ActiveStorage # # When a video's angle is 90 or 270 degrees, its width and height are automatically swapped for convenience. # - # This analyzer requires the {ffmpeg}[https://www.ffmpeg.org] system library, which is not provided by Rails. + # This analyzer requires the {FFmpeg}[https://www.ffmpeg.org] system library, which is not provided by Rails. class Analyzer::VideoAnalyzer < Analyzer def self.accept?(blob) blob.video? @@ -107,7 +107,7 @@ module ActiveStorage JSON.parse(output.read) end rescue Errno::ENOENT - logger.info "Skipping video analysis because ffmpeg isn't installed" + logger.info "Skipping video analysis because FFmpeg isn't installed" {} end diff --git a/activestorage/lib/active_storage/attached.rb b/activestorage/lib/active_storage/attached.rb index c08fd56652..b540f85fbe 100644 --- a/activestorage/lib/active_storage/attached.rb +++ b/activestorage/lib/active_storage/attached.rb @@ -1,40 +1,25 @@ # frozen_string_literal: true -require "action_dispatch" -require "action_dispatch/http/upload" require "active_support/core_ext/module/delegation" module ActiveStorage # Abstract base class for the concrete ActiveStorage::Attached::One and ActiveStorage::Attached::Many # classes that both provide proxy access to the blob association for a record. class Attached - attr_reader :name, :record, :dependent + attr_reader :name, :record - def initialize(name, record, dependent:) - @name, @record, @dependent = name, record, dependent + def initialize(name, record) + @name, @record = name, record end private - def create_blob_from(attachable) - case attachable - when ActiveStorage::Blob - attachable - when ActionDispatch::Http::UploadedFile, Rack::Test::UploadedFile - ActiveStorage::Blob.create_after_upload! \ - io: attachable.open, - filename: attachable.original_filename, - content_type: attachable.content_type - when Hash - ActiveStorage::Blob.create_after_upload!(attachable) - when String - ActiveStorage::Blob.find_signed(attachable) - else - nil - end + def change + record.attachment_changes[name] end end end +require "active_storage/attached/model" require "active_storage/attached/one" require "active_storage/attached/many" -require "active_storage/attached/macros" +require "active_storage/attached/changes" diff --git a/activestorage/lib/active_storage/attached/changes.rb b/activestorage/lib/active_storage/attached/changes.rb new file mode 100644 index 0000000000..1db3906a63 --- /dev/null +++ b/activestorage/lib/active_storage/attached/changes.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module ActiveStorage + module Attached::Changes #:nodoc: + extend ActiveSupport::Autoload + + eager_autoload do + autoload :CreateOne + autoload :CreateMany + autoload :CreateOneOfMany + + autoload :DeleteOne + autoload :DeleteMany + end + end +end diff --git a/activestorage/lib/active_storage/attached/changes/create_many.rb b/activestorage/lib/active_storage/attached/changes/create_many.rb new file mode 100644 index 0000000000..a7a8553e0f --- /dev/null +++ b/activestorage/lib/active_storage/attached/changes/create_many.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +module ActiveStorage + class Attached::Changes::CreateMany #:nodoc: + attr_reader :name, :record, :attachables + + def initialize(name, record, attachables) + @name, @record, @attachables = name, record, Array(attachables) + end + + def attachments + @attachments ||= subchanges.collect(&:attachment) + end + + def blobs + @blobs ||= subchanges.collect(&:blob) + end + + def upload + subchanges.each(&:upload) + end + + def save + assign_associated_attachments + reset_associated_blobs + end + + private + def subchanges + @subchanges ||= attachables.collect { |attachable| build_subchange_from(attachable) } + end + + def build_subchange_from(attachable) + ActiveStorage::Attached::Changes::CreateOneOfMany.new(name, record, attachable) + end + + + def assign_associated_attachments + record.public_send("#{name}_attachments=", attachments) + end + + def reset_associated_blobs + record.public_send("#{name}_blobs").reset + end + end +end diff --git a/activestorage/lib/active_storage/attached/changes/create_one.rb b/activestorage/lib/active_storage/attached/changes/create_one.rb new file mode 100644 index 0000000000..5812fd2b08 --- /dev/null +++ b/activestorage/lib/active_storage/attached/changes/create_one.rb @@ -0,0 +1,68 @@ +# frozen_string_literal: true + +require "action_dispatch" +require "action_dispatch/http/upload" + +module ActiveStorage + class Attached::Changes::CreateOne #:nodoc: + attr_reader :name, :record, :attachable + + def initialize(name, record, attachable) + @name, @record, @attachable = name, record, attachable + end + + def attachment + @attachment ||= find_or_build_attachment + end + + def blob + @blob ||= find_or_build_blob + end + + def upload + case attachable + when ActionDispatch::Http::UploadedFile, Rack::Test::UploadedFile + blob.upload_without_unfurling(attachable.open) + when Hash + blob.upload_without_unfurling(attachable.fetch(:io)) + end + end + + def save + record.public_send("#{name}_attachment=", attachment) + end + + private + def find_or_build_attachment + find_attachment || build_attachment + end + + def find_attachment + if record.public_send("#{name}_blob") == blob + record.public_send("#{name}_attachment") + end + end + + def build_attachment + ActiveStorage::Attachment.new(record: record, name: name, blob: blob) + end + + def find_or_build_blob + case attachable + when ActiveStorage::Blob + attachable + when ActionDispatch::Http::UploadedFile, Rack::Test::UploadedFile + ActiveStorage::Blob.build_after_unfurling \ + io: attachable.open, + filename: attachable.original_filename, + content_type: attachable.content_type + when Hash + ActiveStorage::Blob.build_after_unfurling(attachable) + when String + ActiveStorage::Blob.find_signed(attachable) + else + raise ArgumentError, "Could not find or build blob: expected attachable, got #{attachable.inspect}" + end + end + end +end diff --git a/activestorage/lib/active_storage/attached/changes/create_one_of_many.rb b/activestorage/lib/active_storage/attached/changes/create_one_of_many.rb new file mode 100644 index 0000000000..7268e87316 --- /dev/null +++ b/activestorage/lib/active_storage/attached/changes/create_one_of_many.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +module ActiveStorage + class Attached::Changes::CreateOneOfMany < Attached::Changes::CreateOne #:nodoc: + private + def find_attachment + record.public_send("#{name}_attachments").detect { |attachment| attachment.blob_id == blob.id } + end + end +end diff --git a/activestorage/lib/active_storage/attached/changes/delete_many.rb b/activestorage/lib/active_storage/attached/changes/delete_many.rb new file mode 100644 index 0000000000..6cbd1158dc --- /dev/null +++ b/activestorage/lib/active_storage/attached/changes/delete_many.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module ActiveStorage + class Attached::Changes::DeleteMany #:nodoc: + attr_reader :name, :record + + def initialize(name, record) + @name, @record = name, record + end + + def attachments + ActiveStorage::Attachment.none + end + + def blobs + ActiveStorage::Blob.none + end + + def save + record.public_send("#{name}_attachments=", []) + end + end +end diff --git a/activestorage/lib/active_storage/attached/changes/delete_one.rb b/activestorage/lib/active_storage/attached/changes/delete_one.rb new file mode 100644 index 0000000000..2f7d356613 --- /dev/null +++ b/activestorage/lib/active_storage/attached/changes/delete_one.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module ActiveStorage + class Attached::Changes::DeleteOne #:nodoc: + attr_reader :name, :record + + def initialize(name, record) + @name, @record = name, record + end + + def attachment + nil + end + + def save + record.public_send("#{name}_attachment=", nil) + end + end +end diff --git a/activestorage/lib/active_storage/attached/macros.rb b/activestorage/lib/active_storage/attached/macros.rb deleted file mode 100644 index f99cf35680..0000000000 --- a/activestorage/lib/active_storage/attached/macros.rb +++ /dev/null @@ -1,110 +0,0 @@ -# frozen_string_literal: true - -module ActiveStorage - # Provides the class-level DSL for declaring that an Active Record model has attached blobs. - module Attached::Macros - # Specifies the relation between a single attachment and the model. - # - # class User < ActiveRecord::Base - # has_one_attached :avatar - # end - # - # There is no column defined on the model side, Active Storage takes - # care of the mapping between your records and the attachment. - # - # To avoid N+1 queries, you can include the attached blobs in your query like so: - # - # User.with_attached_avatar - # - # Under the covers, this relationship is implemented as a +has_one+ association to a - # ActiveStorage::Attachment record and a +has_one-through+ association to a - # ActiveStorage::Blob record. These associations are available as +avatar_attachment+ - # and +avatar_blob+. But you shouldn't need to work with these associations directly in - # most circumstances. - # - # The system has been designed to having you go through the ActiveStorage::Attached::One - # proxy that provides the dynamic proxy to the associations and factory methods, like +attach+. - # - # If the +:dependent+ option isn't set, the attachment will be purged - # (i.e. destroyed) whenever the record is destroyed. - def has_one_attached(name, dependent: :purge_later) - generated_association_methods.class_eval <<-CODE, __FILE__, __LINE__ + 1 - def #{name} - @active_storage_attached_#{name} ||= ActiveStorage::Attached::One.new("#{name}", self, dependent: #{dependent == :purge_later ? ":purge_later" : "false"}) - end - - def #{name}=(attachable) - #{name}.attach(attachable) - end - CODE - - has_one :"#{name}_attachment", -> { where(name: name) }, class_name: "ActiveStorage::Attachment", as: :record, inverse_of: :record, dependent: false - has_one :"#{name}_blob", through: :"#{name}_attachment", class_name: "ActiveStorage::Blob", source: :blob - - scope :"with_attached_#{name}", -> { includes("#{name}_attachment": :blob) } - - if dependent == :purge_later - after_destroy_commit { public_send(name).purge_later } - else - before_destroy { public_send(name).detach } - end - end - - # Specifies the relation between multiple attachments and the model. - # - # class Gallery < ActiveRecord::Base - # has_many_attached :photos - # end - # - # There are no columns defined on the model side, Active Storage takes - # care of the mapping between your records and the attachments. - # - # To avoid N+1 queries, you can include the attached blobs in your query like so: - # - # Gallery.where(user: Current.user).with_attached_photos - # - # Under the covers, this relationship is implemented as a +has_many+ association to a - # ActiveStorage::Attachment record and a +has_many-through+ association to a - # ActiveStorage::Blob record. These associations are available as +photos_attachments+ - # and +photos_blobs+. But you shouldn't need to work with these associations directly in - # most circumstances. - # - # The system has been designed to having you go through the ActiveStorage::Attached::Many - # proxy that provides the dynamic proxy to the associations and factory methods, like +#attach+. - # - # If the +:dependent+ option isn't set, all the attachments will be purged - # (i.e. destroyed) whenever the record is destroyed. - def has_many_attached(name, dependent: :purge_later) - generated_association_methods.class_eval <<-CODE, __FILE__, __LINE__ + 1 - def #{name} - @active_storage_attached_#{name} ||= ActiveStorage::Attached::Many.new("#{name}", self, dependent: #{dependent == :purge_later ? ":purge_later" : "false"}) - end - - def #{name}=(attachables) - #{name}.attach(attachables) - end - CODE - - has_many :"#{name}_attachments", -> { where(name: name) }, as: :record, class_name: "ActiveStorage::Attachment", inverse_of: :record, dependent: false do - def purge - each(&:purge) - reset - end - - def purge_later - each(&:purge_later) - reset - end - end - has_many :"#{name}_blobs", through: :"#{name}_attachments", class_name: "ActiveStorage::Blob", source: :blob - - scope :"with_attached_#{name}", -> { includes("#{name}_attachments": :blob) } - - if dependent == :purge_later - after_destroy_commit { public_send(name).purge_later } - else - before_destroy { public_send(name).detach } - end - end - end -end diff --git a/activestorage/lib/active_storage/attached/many.rb b/activestorage/lib/active_storage/attached/many.rb index d61acb6fad..25f88284df 100644 --- a/activestorage/lib/active_storage/attached/many.rb +++ b/activestorage/lib/active_storage/attached/many.rb @@ -9,22 +9,29 @@ module ActiveStorage # # All methods called on this proxy object that aren't listed here will automatically be delegated to +attachments+. def attachments - record.public_send("#{name}_attachments") + change.present? ? change.attachments : record.public_send("#{name}_attachments") end - # Associates one or several attachments with the current record, saving them to the database. + # Returns all attached blobs. + def blobs + change.present? ? change.blobs : record.public_send("#{name}_blobs") + end + + # Attaches one or more +attachables+ to the record. + # + # If the record is persisted and unchanged, the attachments are saved to + # the database immediately. Otherwise, they'll be saved to the DB when the + # record is next saved. # # document.images.attach(params[:images]) # Array of ActionDispatch::Http::UploadedFile objects # document.images.attach(params[:signed_blob_id]) # Signed reference to blob from direct upload # document.images.attach(io: File.open("/path/to/racecar.jpg"), filename: "racecar.jpg", content_type: "image/jpg") # document.images.attach([ first_blob, second_blob ]) def attach(*attachables) - attachables.flatten.collect do |attachable| - if record.new_record? - attachments.build(record: record, blob: create_blob_from(attachable)) - else - attachments.create!(record: record, blob: create_blob_from(attachable)) - end + if record.persisted? && !record.changed? + record.update(name => blobs + attachables.flatten) + else + record.public_send("#{name}=", blobs + attachables.flatten) end end @@ -41,7 +48,7 @@ module ActiveStorage # Deletes associated attachments without purging them, leaving their respective blobs in place. def detach - attachments.destroy_all if attached? + attachments.delete_all if attached? end ## @@ -50,7 +57,6 @@ module ActiveStorage # Directly purges each associated attachment (i.e. destroys the blobs and # attachments and deletes the files on the service). - ## # :method: purge_later # diff --git a/activestorage/lib/active_storage/attached/model.rb b/activestorage/lib/active_storage/attached/model.rb new file mode 100644 index 0000000000..ae7f0685f2 --- /dev/null +++ b/activestorage/lib/active_storage/attached/model.rb @@ -0,0 +1,140 @@ +# frozen_string_literal: true + +module ActiveStorage + # Provides the class-level DSL for declaring an Active Record model's attachments. + module Attached::Model + extend ActiveSupport::Concern + + class_methods do + # Specifies the relation between a single attachment and the model. + # + # class User < ActiveRecord::Base + # has_one_attached :avatar + # end + # + # There is no column defined on the model side, Active Storage takes + # care of the mapping between your records and the attachment. + # + # To avoid N+1 queries, you can include the attached blobs in your query like so: + # + # User.with_attached_avatar + # + # Under the covers, this relationship is implemented as a +has_one+ association to a + # ActiveStorage::Attachment record and a +has_one-through+ association to a + # ActiveStorage::Blob record. These associations are available as +avatar_attachment+ + # and +avatar_blob+. But you shouldn't need to work with these associations directly in + # most circumstances. + # + # The system has been designed to having you go through the ActiveStorage::Attached::One + # proxy that provides the dynamic proxy to the associations and factory methods, like +attach+. + # + # If the +:dependent+ option isn't set, the attachment will be purged + # (i.e. destroyed) whenever the record is destroyed. + def has_one_attached(name, dependent: :purge_later) + generated_association_methods.class_eval <<-CODE, __FILE__, __LINE__ + 1 + def #{name} + @active_storage_attached_#{name} ||= ActiveStorage::Attached::One.new("#{name}", self) + end + + def #{name}=(attachable) + attachment_changes["#{name}"] = + if attachable.nil? + ActiveStorage::Attached::Changes::DeleteOne.new("#{name}", self) + else + ActiveStorage::Attached::Changes::CreateOne.new("#{name}", self, attachable) + end + end + CODE + + has_one :"#{name}_attachment", -> { where(name: name) }, class_name: "ActiveStorage::Attachment", as: :record, inverse_of: :record, dependent: :destroy + has_one :"#{name}_blob", through: :"#{name}_attachment", class_name: "ActiveStorage::Blob", source: :blob + + scope :"with_attached_#{name}", -> { includes("#{name}_attachment": :blob) } + + after_save { attachment_changes[name.to_s]&.save } + + after_commit(on: %i[ create update ]) { attachment_changes.delete(name.to_s).try(:upload) } + + ActiveRecord::Reflection.add_attachment_reflection( + self, + name, + ActiveRecord::Reflection.create(:has_one_attached, name, nil, { dependent: dependent }, self) + ) + end + + # Specifies the relation between multiple attachments and the model. + # + # class Gallery < ActiveRecord::Base + # has_many_attached :photos + # end + # + # There are no columns defined on the model side, Active Storage takes + # care of the mapping between your records and the attachments. + # + # To avoid N+1 queries, you can include the attached blobs in your query like so: + # + # Gallery.where(user: Current.user).with_attached_photos + # + # Under the covers, this relationship is implemented as a +has_many+ association to a + # ActiveStorage::Attachment record and a +has_many-through+ association to a + # ActiveStorage::Blob record. These associations are available as +photos_attachments+ + # and +photos_blobs+. But you shouldn't need to work with these associations directly in + # most circumstances. + # + # The system has been designed to having you go through the ActiveStorage::Attached::Many + # proxy that provides the dynamic proxy to the associations and factory methods, like +#attach+. + # + # If the +:dependent+ option isn't set, all the attachments will be purged + # (i.e. destroyed) whenever the record is destroyed. + def has_many_attached(name, dependent: :purge_later) + generated_association_methods.class_eval <<-CODE, __FILE__, __LINE__ + 1 + def #{name} + @active_storage_attached_#{name} ||= ActiveStorage::Attached::Many.new("#{name}", self) + end + + def #{name}=(attachables) + attachment_changes["#{name}"] = + if attachables.nil? || Array(attachables).none? + ActiveStorage::Attached::Changes::DeleteMany.new("#{name}", self) + else + ActiveStorage::Attached::Changes::CreateMany.new("#{name}", self, attachables) + end + end + CODE + + has_many :"#{name}_attachments", -> { where(name: name) }, as: :record, class_name: "ActiveStorage::Attachment", inverse_of: :record, dependent: :destroy do + def purge + each(&:purge) + reset + end + + def purge_later + each(&:purge_later) + reset + end + end + has_many :"#{name}_blobs", through: :"#{name}_attachments", class_name: "ActiveStorage::Blob", source: :blob + + scope :"with_attached_#{name}", -> { includes("#{name}_attachments": :blob) } + + after_save { attachment_changes[name.to_s]&.save } + + after_commit(on: %i[ create update ]) { attachment_changes.delete(name.to_s).try(:upload) } + + ActiveRecord::Reflection.add_attachment_reflection( + self, + name, + ActiveRecord::Reflection.create(:has_many_attached, name, nil, { dependent: dependent }, self) + ) + end + end + + def attachment_changes #:nodoc: + @attachment_changes ||= {} + end + + def reload(*) #:nodoc: + super.tap { @attachment_changes = nil } + end + end +end diff --git a/activestorage/lib/active_storage/attached/one.rb b/activestorage/lib/active_storage/attached/one.rb index f992cb5f84..c039226fcd 100644 --- a/activestorage/lib/active_storage/attached/one.rb +++ b/activestorage/lib/active_storage/attached/one.rb @@ -10,30 +10,28 @@ module ActiveStorage # You don't have to call this method to access the attachment's methods as # they are all available at the model level. def attachment - record.public_send("#{name}_attachment") + change.present? ? change.attachment : record.public_send("#{name}_attachment") end def blank? - attachment.blank? + !attached? end - # Associates a given attachment with the current record, saving it to the database. + # Attaches an +attachable+ to the record. + # + # If the record is persisted and unchanged, the attachment is saved to + # the database immediately. Otherwise, it'll be saved to the DB when the + # record is next saved. # # person.avatar.attach(params[:avatar]) # ActionDispatch::Http::UploadedFile object # person.avatar.attach(params[:signed_blob_id]) # Signed reference to blob from direct upload # person.avatar.attach(io: File.open("/path/to/face.jpg"), filename: "face.jpg", content_type: "image/jpg") # person.avatar.attach(avatar_blob) # ActiveStorage::Blob object def attach(attachable) - blob_was = blob if attached? - blob = create_blob_from(attachable) - - unless blob == blob_was - transaction do - detach - write_attachment build_attachment(blob: blob) - end - - blob_was.purge_later if blob_was && dependent == :purge_later + if record.persisted? && !record.changed? + record.update(name => attachable) + else + record.public_send("#{name}=", attachable) end end @@ -51,7 +49,7 @@ module ActiveStorage # Deletes the attachment without purging it, leaving its blob in place. def detach if attached? - attachment.destroy + attachment.delete write_attachment nil end end @@ -69,16 +67,11 @@ module ActiveStorage def purge_later if attached? attachment.purge_later + write_attachment nil end end private - delegate :transaction, to: :record - - def build_attachment(blob:) - ActiveStorage::Attachment.new(record: record, name: name, blob: blob) - end - def write_attachment(attachment) record.public_send("#{name}_attachment=", attachment) end diff --git a/activestorage/lib/active_storage/downloader.rb b/activestorage/lib/active_storage/downloader.rb index 0e7039e104..87be6efb05 100644 --- a/activestorage/lib/active_storage/downloader.rb +++ b/activestorage/lib/active_storage/downloader.rb @@ -10,6 +10,7 @@ module ActiveStorage def download_blob_to_tempfile open_tempfile do |file| download_blob_to file + verify_integrity_of file yield file end end @@ -18,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 @@ -34,8 +35,10 @@ module ActiveStorage file.rewind end - def tempfile_extension_with_delimiter - blob.filename.extension_with_delimiter + def verify_integrity_of(file) + unless Digest::MD5.file(file).base64digest == blob.checksum + raise ActiveStorage::IntegrityError + end end end end diff --git a/activestorage/lib/active_storage/engine.rb b/activestorage/lib/active_storage/engine.rb index 99588cdd4b..9d6a27eabe 100644 --- a/activestorage/lib/active_storage/engine.rb +++ b/activestorage/lib/active_storage/engine.rb @@ -10,6 +10,8 @@ require "active_storage/previewer/video_previewer" require "active_storage/analyzer/image_analyzer" require "active_storage/analyzer/video_analyzer" +require "active_storage/reflection" + module ActiveStorage class Engine < Rails::Engine # :nodoc: isolate_namespace ActiveStorage @@ -52,6 +54,7 @@ module ActiveStorage ActiveStorage.variable_content_types = app.config.active_storage.variable_content_types || [] ActiveStorage.content_types_to_serve_as_binary = app.config.active_storage.content_types_to_serve_as_binary || [] + ActiveStorage.service_urls_expire_in = app.config.active_storage.service_urls_expire_in || 5.minutes end end @@ -59,7 +62,7 @@ module ActiveStorage require "active_storage/attached" ActiveSupport.on_load(:active_record) do - extend ActiveStorage::Attached::Macros + include ActiveStorage::Attached::Model end end @@ -95,5 +98,12 @@ module ActiveStorage end end end + + initializer "active_storage.reflection" do + ActiveSupport.on_load(:active_record) do + include Reflection::ActiveRecordExtensions + ActiveRecord::Reflection.singleton_class.prepend(Reflection::ReflectionExtension) + end + end end end diff --git a/activestorage/lib/active_storage/errors.rb b/activestorage/lib/active_storage/errors.rb index f099b13f5b..bedcd080c4 100644 --- a/activestorage/lib/active_storage/errors.rb +++ b/activestorage/lib/active_storage/errors.rb @@ -4,4 +4,8 @@ module ActiveStorage class InvariableError < StandardError; end class UnpreviewableError < StandardError; end class UnrepresentableError < StandardError; end + + # Raised when uploaded or downloaded data does not match a precomputed checksum. + # Indicates that a network error or a software bug caused data corruption. + class IntegrityError < StandardError; end end diff --git a/activestorage/lib/active_storage/previewer.rb b/activestorage/lib/active_storage/previewer.rb index bff5e42d41..fb202f029a 100644 --- a/activestorage/lib/active_storage/previewer.rb +++ b/activestorage/lib/active_storage/previewer.rb @@ -31,7 +31,7 @@ module ActiveStorage # Executes a system command, capturing its binary output in a tempfile. Yields the tempfile. # - # Use this method to shell out to a system library (e.g. mupdf or ffmpeg) for preview image + # Use this method to shell out to a system library (e.g. muPDF or FFmpeg) for preview image # generation. The resulting tempfile can be used as the +:io+ value in an attachable Hash: # # def preview @@ -44,16 +44,17 @@ module ActiveStorage # # The output tempfile is opened in the directory returned by #tempdir. def draw(*argv) #:doc: - ActiveSupport::Notifications.instrument("preview.active_storage") do - open_tempfile_for_drawing do |file| + open_tempfile do |file| + instrument :preview, key: blob.key do capture(*argv, to: file) - yield file end + + yield file end end - def open_tempfile_for_drawing - tempfile = Tempfile.open("ActiveStorage", tempdir) + def open_tempfile + tempfile = Tempfile.open("ActiveStorage-", tempdir) begin yield tempfile @@ -62,6 +63,10 @@ module ActiveStorage end end + def instrument(operation, payload = {}, &block) + ActiveSupport::Notifications.instrument "#{operation}.active_storage", payload, &block + end + def capture(*argv, to:) to.binmode IO.popen(argv, err: File::NULL) { |out| IO.copy_stream(out, to) } diff --git a/activestorage/lib/active_storage/previewer/poppler_pdf_previewer.rb b/activestorage/lib/active_storage/previewer/poppler_pdf_previewer.rb index 2a787362cf..69eb617d7b 100644 --- a/activestorage/lib/active_storage/previewer/poppler_pdf_previewer.rb +++ b/activestorage/lib/active_storage/previewer/poppler_pdf_previewer.rb @@ -12,7 +12,7 @@ module ActiveStorage end def pdftoppm_exists? - return @pdftoppm_exists unless @pdftoppm_exists.nil? + return @pdftoppm_exists if defined?(@pdftoppm_exists) @pdftoppm_exists = system(pdftoppm_path, "-v", out: File::NULL, err: File::NULL) end diff --git a/activestorage/lib/active_storage/reflection.rb b/activestorage/lib/active_storage/reflection.rb new file mode 100644 index 0000000000..ce248c88b5 --- /dev/null +++ b/activestorage/lib/active_storage/reflection.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true + +module ActiveStorage + module Reflection + # Holds all the metadata about a has_one_attached attachment as it was + # specified in the Active Record class. + class HasOneAttachedReflection < ActiveRecord::Reflection::MacroReflection #:nodoc: + def macro + :has_one_attached + end + end + + # Holds all the metadata about a has_many_attached attachment as it was + # specified in the Active Record class. + class HasManyAttachedReflection < ActiveRecord::Reflection::MacroReflection #:nodoc: + def macro + :has_many_attached + end + end + + module ReflectionExtension # :nodoc: + def add_attachment_reflection(model, name, reflection) + model.attachment_reflections = model.attachment_reflections.merge(name.to_s => reflection) + end + + private + def reflection_class_for(macro) + case macro + when :has_one_attached + HasOneAttachedReflection + when :has_many_attached + HasManyAttachedReflection + else + super + end + end + end + + module ActiveRecordExtensions + extend ActiveSupport::Concern + + included do + class_attribute :attachment_reflections, instance_writer: false, default: {} + end + + module ClassMethods + # Returns an array of reflection objects for all the attachments in the + # class. + def reflect_on_all_attachments + attachment_reflections.values + end + + # Returns the reflection object for the named +attachment+. + # + # User.reflect_on_attachment(:avatar) + # # => the avatar reflection + # + def reflect_on_attachment(attachment) + attachment_reflections[attachment.to_s] + end + end + end + end +end diff --git a/activestorage/lib/active_storage/service.rb b/activestorage/lib/active_storage/service.rb index 949969fc95..f915518f52 100644 --- a/activestorage/lib/active_storage/service.rb +++ b/activestorage/lib/active_storage/service.rb @@ -3,8 +3,6 @@ require "active_storage/log_subscriber" module ActiveStorage - class IntegrityError < StandardError; end - # Abstract class serving as an interface for concrete services. # # The available services are: @@ -41,8 +39,6 @@ module ActiveStorage extend ActiveSupport::Autoload autoload :Configurator - class_attribute :url_expires_in, default: 5.minutes - class << self # Configure an Active Storage service by name from a set of configurations, # typically loaded from a YAML file. The Active Storage engine uses this @@ -94,7 +90,7 @@ module ActiveStorage end # Returns a signed, temporary URL for the file at the +key+. The URL will be valid for the amount - # of seconds specified in +expires_in+. You most also provide the +disposition+ (+:inline+ or +:attachment+), + # of seconds specified in +expires_in+. You must also provide the +disposition+ (+:inline+ or +:attachment+), # +filename+, and +content_type+ that you wish the file to be served with on request. def url(key, expires_in:, disposition:, filename:, content_type:) raise NotImplementedError diff --git a/activestorage/lib/active_storage/service/disk_service.rb b/activestorage/lib/active_storage/service/disk_service.rb index b1b6f1ddcf..9f304b7e01 100644 --- a/activestorage/lib/active_storage/service/disk_service.rb +++ b/activestorage/lib/active_storage/service/disk_service.rb @@ -117,11 +117,11 @@ module ActiveStorage { "Content-Type" => content_type } end - private - def path_for(key) - File.join root, folder_for(key), key - end + def path_for(key) #:nodoc: + File.join root, folder_for(key), key + end + private def folder_for(key) [ key[0..1], key[2..3] ].join("/") end diff --git a/activestorage/lib/active_storage/service/gcs_service.rb b/activestorage/lib/active_storage/service/gcs_service.rb index 38acef81f4..fdde01d4a3 100644 --- a/activestorage/lib/active_storage/service/gcs_service.rb +++ b/activestorage/lib/active_storage/service/gcs_service.rb @@ -6,7 +6,6 @@ require "google/cloud/storage" require "net/http" require "active_support/core_ext/object/to_query" -require "active_storage/filename" module ActiveStorage # Wraps the Google Cloud Storage as an Active Storage service. See ActiveStorage::Service for the generic API diff --git a/activestorage/lib/tasks/activestorage.rake b/activestorage/lib/tasks/activestorage.rake index 296e91afa1..ac254d717f 100644 --- a/activestorage/lib/tasks/activestorage.rake +++ b/activestorage/lib/tasks/activestorage.rake @@ -1,6 +1,9 @@ # frozen_string_literal: true namespace :active_storage do + # Prevent migration installation task from showing up twice. + Rake::Task["install:migrations"].clear_comments + desc "Copy over the migration needed to the application" task install: :environment do if Rake::Task.task_defined?("active_storage:install:migrations") diff --git a/activestorage/test/controllers/disk_controller_test.rb b/activestorage/test/controllers/disk_controller_test.rb index 9af7c83bdf..c053052f6f 100644 --- a/activestorage/test/controllers/disk_controller_test.rb +++ b/activestorage/test/controllers/disk_controller_test.rb @@ -6,8 +6,8 @@ require "database/setup" class ActiveStorage::DiskControllerTest < ActionDispatch::IntegrationTest test "showing blob inline" do blob = create_blob - get blob.service_url + assert_response :ok assert_equal "inline; filename=\"hello.txt\"; filename*=UTF-8''hello.txt", response.headers["Content-Disposition"] assert_equal "text/plain", response.headers["Content-Type"] assert_equal "Hello world!", response.body @@ -15,13 +15,22 @@ class ActiveStorage::DiskControllerTest < ActionDispatch::IntegrationTest test "showing blob as attachment" do blob = create_blob - get blob.service_url(disposition: :attachment) + assert_response :ok assert_equal "attachment; filename=\"hello.txt\"; filename*=UTF-8''hello.txt", response.headers["Content-Disposition"] assert_equal "text/plain", response.headers["Content-Type"] assert_equal "Hello world!", response.body end + test "showing blob range inline" do + blob = create_blob + get blob.service_url, headers: { "Range" => "bytes=5-9" } + assert_response :partial_content + assert_equal "inline; filename=\"hello.txt\"; filename*=UTF-8''hello.txt", response.headers["Content-Disposition"] + assert_equal "text/plain", response.headers["Content-Type"] + assert_equal " worl", response.body + end + test "directly uploading blob with integrity" do data = "Something else entirely!" @@ -58,4 +67,10 @@ class ActiveStorage::DiskControllerTest < ActionDispatch::IntegrationTest assert_response :unprocessable_entity assert_not blob.service.exist?(blob.key) end + + test "directly uploading blob with invalid token" do + put update_rails_disk_service_url(encoded_token: "invalid"), + params: "Something else entirely!", headers: { "Content-Type" => "text/plain" } + assert_response :not_found + end end diff --git a/activestorage/test/jobs/purge_job_test.rb b/activestorage/test/jobs/purge_job_test.rb new file mode 100644 index 0000000000..ed4100b78d --- /dev/null +++ b/activestorage/test/jobs/purge_job_test.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +require "test_helper" +require "database/setup" + +class ActiveStorage::PurgeJobTest < ActiveJob::TestCase + setup { @blob = create_blob } + + test "purges" do + assert_difference -> { ActiveStorage::Blob.count }, -1 do + ActiveStorage::PurgeJob.perform_now @blob + end + + assert_not ActiveStorage::Blob.exists?(@blob.id) + assert_not ActiveStorage::Blob.service.exist?(@blob.key) + end + + test "ignores missing blob" do + @blob.purge + + perform_enqueued_jobs do + assert_nothing_raised do + ActiveStorage::PurgeJob.perform_later @blob + end + end + end + + test "ignores attached blob" do + User.create! name: "DHH", avatar: @blob + + perform_enqueued_jobs do + assert_nothing_raised do + ActiveStorage::PurgeJob.perform_later @blob + end + end + end +end diff --git a/activestorage/test/models/attached/many_test.rb b/activestorage/test/models/attached/many_test.rb new file mode 100644 index 0000000000..334254d099 --- /dev/null +++ b/activestorage/test/models/attached/many_test.rb @@ -0,0 +1,540 @@ +# frozen_string_literal: true + +require "test_helper" +require "database/setup" + +class ActiveStorage::ManyAttachedTest < ActiveSupport::TestCase + include ActiveJob::TestHelper + + setup do + @user = User.create!(name: "Josh") + end + + teardown { ActiveStorage::Blob.all.each(&:delete) } + + test "attaching existing blobs to an existing record" do + @user.highlights.attach create_blob(filename: "funky.jpg"), create_blob(filename: "town.jpg") + assert_equal "funky.jpg", @user.highlights.first.filename.to_s + assert_equal "town.jpg", @user.highlights.second.filename.to_s + end + + test "attaching existing blobs from signed IDs to an existing record" do + @user.highlights.attach create_blob(filename: "funky.jpg").signed_id, create_blob(filename: "town.jpg").signed_id + assert_equal "funky.jpg", @user.highlights.first.filename.to_s + assert_equal "town.jpg", @user.highlights.second.filename.to_s + end + + test "attaching new blobs from Hashes to an existing record" do + @user.highlights.attach( + { io: StringIO.new("STUFF"), filename: "funky.jpg", content_type: "image/jpg" }, + { io: StringIO.new("THINGS"), filename: "town.jpg", content_type: "image/jpeg" }) + + assert_equal "funky.jpg", @user.highlights.first.filename.to_s + assert_equal "town.jpg", @user.highlights.second.filename.to_s + end + + test "attaching new blobs from uploaded files to an existing record" do + @user.highlights.attach fixture_file_upload("racecar.jpg"), fixture_file_upload("video.mp4") + assert_equal "racecar.jpg", @user.highlights.first.filename.to_s + assert_equal "video.mp4", @user.highlights.second.filename.to_s + end + + test "attaching existing blobs to an existing, changed record" do + @user.name = "Tina" + assert @user.changed? + + @user.highlights.attach create_blob(filename: "funky.jpg"), create_blob(filename: "town.jpg") + assert_equal "funky.jpg", @user.highlights.first.filename.to_s + assert_equal "town.jpg", @user.highlights.second.filename.to_s + assert_not @user.highlights.first.persisted? + assert_not @user.highlights.second.persisted? + assert @user.will_save_change_to_name? + + @user.save! + assert_equal "funky.jpg", @user.highlights.reload.first.filename.to_s + assert_equal "town.jpg", @user.highlights.second.filename.to_s + end + + test "attaching existing blobs from signed IDs to an existing, changed record" do + @user.name = "Tina" + assert @user.changed? + + @user.highlights.attach create_blob(filename: "funky.jpg").signed_id, create_blob(filename: "town.jpg").signed_id + assert_equal "funky.jpg", @user.highlights.first.filename.to_s + assert_equal "town.jpg", @user.highlights.second.filename.to_s + assert_not @user.highlights.first.persisted? + assert_not @user.highlights.second.persisted? + assert @user.will_save_change_to_name? + + @user.save! + assert_equal "funky.jpg", @user.highlights.reload.first.filename.to_s + assert_equal "town.jpg", @user.highlights.second.filename.to_s + end + + test "attaching new blobs from Hashes to an existing, changed record" do + @user.name = "Tina" + assert @user.changed? + + @user.highlights.attach( + { io: StringIO.new("STUFF"), filename: "funky.jpg", content_type: "image/jpg" }, + { io: StringIO.new("THINGS"), filename: "town.jpg", content_type: "image/jpeg" }) + + assert_equal "funky.jpg", @user.highlights.first.filename.to_s + assert_equal "town.jpg", @user.highlights.second.filename.to_s + assert_not @user.highlights.first.persisted? + assert_not @user.highlights.second.persisted? + assert @user.will_save_change_to_name? + + @user.save! + assert_equal "funky.jpg", @user.highlights.reload.first.filename.to_s + assert_equal "town.jpg", @user.highlights.second.filename.to_s + end + + test "attaching new blobs from uploaded files to an existing, changed record" do + @user.name = "Tina" + assert @user.changed? + + @user.highlights.attach fixture_file_upload("racecar.jpg"), fixture_file_upload("video.mp4") + assert_equal "racecar.jpg", @user.highlights.first.filename.to_s + assert_equal "video.mp4", @user.highlights.second.filename.to_s + assert_not @user.highlights.first.persisted? + assert_not @user.highlights.second.persisted? + assert @user.will_save_change_to_name? + + @user.save! + assert_equal "racecar.jpg", @user.highlights.reload.first.filename.to_s + assert_equal "video.mp4", @user.highlights.second.filename.to_s + end + + test "attaching existing blobs to an existing record one at a time" do + @user.highlights.attach create_blob(filename: "funky.jpg") + @user.highlights.attach create_blob(filename: "town.jpg") + assert_equal "funky.jpg", @user.highlights.first.filename.to_s + assert_equal "town.jpg", @user.highlights.second.filename.to_s + + @user.reload + assert_equal "funky.jpg", @user.highlights.first.filename.to_s + assert_equal "town.jpg", @user.highlights.second.filename.to_s + end + + test "updating an existing record to attach existing blobs" do + @user.update! highlights: [ create_file_blob(filename: "racecar.jpg"), create_file_blob(filename: "video.mp4") ] + assert_equal "racecar.jpg", @user.highlights.first.filename.to_s + assert_equal "video.mp4", @user.highlights.second.filename.to_s + end + + test "updating an existing record to attach existing blobs from signed IDs" do + @user.update! highlights: [ create_blob(filename: "funky.jpg").signed_id, create_blob(filename: "town.jpg").signed_id ] + assert_equal "funky.jpg", @user.highlights.first.filename.to_s + assert_equal "town.jpg", @user.highlights.second.filename.to_s + end + + test "successfully updating an existing record to attach new blobs from uploaded files" do + @user.highlights = [ fixture_file_upload("racecar.jpg"), fixture_file_upload("video.mp4") ] + assert_equal "racecar.jpg", @user.highlights.first.filename.to_s + assert_equal "video.mp4", @user.highlights.second.filename.to_s + assert_not ActiveStorage::Blob.service.exist?(@user.highlights.first.key) + assert_not ActiveStorage::Blob.service.exist?(@user.highlights.second.key) + + @user.save! + assert ActiveStorage::Blob.service.exist?(@user.highlights.first.key) + assert ActiveStorage::Blob.service.exist?(@user.highlights.second.key) + end + + test "unsuccessfully updating an existing record to attach new blobs from uploaded files" do + assert_not @user.update(name: "", highlights: [ fixture_file_upload("racecar.jpg"), fixture_file_upload("video.mp4") ]) + assert_equal "racecar.jpg", @user.highlights.first.filename.to_s + assert_equal "video.mp4", @user.highlights.second.filename.to_s + assert_not ActiveStorage::Blob.service.exist?(@user.highlights.first.key) + assert_not ActiveStorage::Blob.service.exist?(@user.highlights.second.key) + end + + test "replacing existing, dependent attachments on an existing record via assign and attach" do + [ create_blob(filename: "funky.jpg"), create_blob(filename: "town.jpg") ].tap do |old_blobs| + @user.highlights.attach old_blobs + + @user.highlights = [] + assert_not @user.highlights.attached? + + perform_enqueued_jobs do + @user.highlights.attach create_blob(filename: "whenever.jpg"), create_blob(filename: "wherever.jpg") + end + + assert_equal "whenever.jpg", @user.highlights.first.filename.to_s + assert_equal "wherever.jpg", @user.highlights.second.filename.to_s + assert_not ActiveStorage::Blob.exists?(old_blobs.first.id) + assert_not ActiveStorage::Blob.exists?(old_blobs.second.id) + assert_not ActiveStorage::Blob.service.exist?(old_blobs.first.key) + assert_not ActiveStorage::Blob.service.exist?(old_blobs.second.key) + end + end + + test "replacing existing, independent attachments on an existing record via assign and attach" do + @user.vlogs.attach create_blob(filename: "funky.mp4"), create_blob(filename: "town.mp4") + + @user.vlogs = [] + assert_not @user.vlogs.attached? + + assert_no_enqueued_jobs only: ActiveStorage::PurgeJob do + @user.vlogs.attach create_blob(filename: "whenever.mp4"), create_blob(filename: "wherever.mp4") + end + + assert_equal "whenever.mp4", @user.vlogs.first.filename.to_s + assert_equal "wherever.mp4", @user.vlogs.second.filename.to_s + end + + test "successfully updating an existing record to replace existing, dependent attachments" do + [ create_blob(filename: "funky.jpg"), create_blob(filename: "town.jpg") ].tap do |old_blobs| + @user.highlights.attach old_blobs + + perform_enqueued_jobs do + @user.update! highlights: [ create_blob(filename: "whenever.jpg"), create_blob(filename: "wherever.jpg") ] + end + + assert_equal "whenever.jpg", @user.highlights.first.filename.to_s + assert_equal "wherever.jpg", @user.highlights.second.filename.to_s + assert_not ActiveStorage::Blob.exists?(old_blobs.first.id) + assert_not ActiveStorage::Blob.exists?(old_blobs.second.id) + assert_not ActiveStorage::Blob.service.exist?(old_blobs.first.key) + assert_not ActiveStorage::Blob.service.exist?(old_blobs.second.key) + end + end + + test "successfully updating an existing record to replace existing, independent attachments" do + @user.vlogs.attach create_blob(filename: "funky.mp4"), create_blob(filename: "town.mp4") + + assert_no_enqueued_jobs only: ActiveStorage::PurgeJob do + @user.update! vlogs: [ create_blob(filename: "whenever.mp4"), create_blob(filename: "wherever.mp4") ] + end + + assert_equal "whenever.mp4", @user.vlogs.first.filename.to_s + assert_equal "wherever.mp4", @user.vlogs.second.filename.to_s + end + + test "unsuccessfully updating an existing record to replace existing attachments" do + @user.highlights.attach create_blob(filename: "funky.jpg"), create_blob(filename: "town.jpg") + + assert_no_enqueued_jobs do + assert_not @user.update(name: "", highlights: [ fixture_file_upload("racecar.jpg"), fixture_file_upload("video.mp4") ]) + end + + assert_equal "racecar.jpg", @user.highlights.first.filename.to_s + assert_equal "video.mp4", @user.highlights.second.filename.to_s + assert_not ActiveStorage::Blob.service.exist?(@user.highlights.first.key) + assert_not ActiveStorage::Blob.service.exist?(@user.highlights.second.key) + end + + test "updating an existing record to attach one new blob and one previously-attached blob" do + [ create_blob(filename: "funky.jpg"), create_blob(filename: "town.jpg") ].tap do |blobs| + @user.highlights.attach blobs.first + + perform_enqueued_jobs do + assert_no_changes -> { @user.highlights_attachments.first.id } do + @user.update! highlights: blobs + end + end + + assert_equal "funky.jpg", @user.highlights.first.filename.to_s + assert_equal "town.jpg", @user.highlights.second.filename.to_s + assert ActiveStorage::Blob.service.exist?(@user.highlights.first.key) + end + end + + test "updating an existing record to remove dependent attachments" do + [ create_blob(filename: "funky.jpg"), create_blob(filename: "town.jpg") ].tap do |blobs| + @user.highlights.attach blobs + + assert_enqueued_with job: ActiveStorage::PurgeJob, args: [ blobs.first ] do + assert_enqueued_with job: ActiveStorage::PurgeJob, args: [ blobs.second ] do + @user.update! highlights: [] + end + end + + assert_not @user.highlights.attached? + end + end + + test "updating an existing record to remove independent attachments" do + [ create_blob(filename: "funky.mp4"), create_blob(filename: "town.mp4") ].tap do |blobs| + @user.vlogs.attach blobs + + assert_no_enqueued_jobs only: ActiveStorage::PurgeJob do + @user.update! vlogs: [] + end + + assert_not @user.vlogs.attached? + end + end + + test "analyzing a new blob from an uploaded file after attaching it to an existing record" do + perform_enqueued_jobs do + @user.highlights.attach fixture_file_upload("racecar.jpg") + end + + assert @user.highlights.reload.first.analyzed? + assert_equal 4104, @user.highlights.first.metadata[:width] + assert_equal 2736, @user.highlights.first.metadata[:height] + end + + test "analyzing a new blob from an uploaded file after attaching it to an existing record via update" do + perform_enqueued_jobs do + @user.update! highlights: [ fixture_file_upload("racecar.jpg") ] + end + + assert @user.highlights.reload.first.analyzed? + assert_equal 4104, @user.highlights.first.metadata[:width] + assert_equal 2736, @user.highlights.first.metadata[:height] + end + + test "analyzing a directly-uploaded blob after attaching it to an existing record" do + perform_enqueued_jobs do + @user.highlights.attach directly_upload_file_blob(filename: "racecar.jpg") + end + + assert @user.highlights.reload.first.analyzed? + assert_equal 4104, @user.highlights.first.metadata[:width] + assert_equal 2736, @user.highlights.first.metadata[:height] + end + + test "analyzing a directly-uploaded blob after attaching it to an existing record via update" do + perform_enqueued_jobs do + @user.update! highlights: [ directly_upload_file_blob(filename: "racecar.jpg") ] + end + + assert @user.highlights.reload.first.analyzed? + assert_equal 4104, @user.highlights.first.metadata[:width] + assert_equal 2736, @user.highlights.first.metadata[:height] + end + + test "attaching existing blobs to a new record" do + User.new(name: "Jason").tap do |user| + user.highlights.attach create_blob(filename: "funky.jpg"), create_blob(filename: "town.jpg") + assert user.new_record? + assert_equal "funky.jpg", user.highlights.first.filename.to_s + assert_equal "town.jpg", user.highlights.second.filename.to_s + + user.save! + assert_equal "funky.jpg", user.highlights.first.filename.to_s + assert_equal "town.jpg", user.highlights.second.filename.to_s + end + end + + test "attaching an existing blob from a signed ID to a new record" do + User.new(name: "Jason").tap do |user| + user.avatar.attach create_blob(filename: "funky.jpg").signed_id + assert user.new_record? + assert_equal "funky.jpg", user.avatar.filename.to_s + + user.save! + assert_equal "funky.jpg", user.reload.avatar.filename.to_s + end + end + + test "attaching new blobs from Hashes to a new record" do + User.new(name: "Jason").tap do |user| + user.highlights.attach( + { io: StringIO.new("STUFF"), filename: "funky.jpg", content_type: "image/jpg" }, + { io: StringIO.new("THINGS"), filename: "town.jpg", content_type: "image/jpg" }) + + assert user.new_record? + assert user.highlights.first.new_record? + assert user.highlights.second.new_record? + assert user.highlights.first.blob.new_record? + assert user.highlights.second.blob.new_record? + assert_equal "funky.jpg", user.highlights.first.filename.to_s + assert_equal "town.jpg", user.highlights.second.filename.to_s + assert_not ActiveStorage::Blob.service.exist?(user.highlights.first.key) + assert_not ActiveStorage::Blob.service.exist?(user.highlights.second.key) + + user.save! + assert user.highlights.first.persisted? + assert user.highlights.second.persisted? + assert user.highlights.first.blob.persisted? + assert user.highlights.second.blob.persisted? + assert_equal "funky.jpg", user.reload.highlights.first.filename.to_s + assert_equal "town.jpg", user.highlights.second.filename.to_s + assert ActiveStorage::Blob.service.exist?(user.highlights.first.key) + assert ActiveStorage::Blob.service.exist?(user.highlights.second.key) + end + end + + test "attaching new blobs from uploaded files to a new record" do + User.new(name: "Jason").tap do |user| + user.highlights.attach fixture_file_upload("racecar.jpg"), fixture_file_upload("video.mp4") + assert user.new_record? + assert user.highlights.first.new_record? + assert user.highlights.second.new_record? + assert user.highlights.first.blob.new_record? + assert user.highlights.second.blob.new_record? + assert_equal "racecar.jpg", user.highlights.first.filename.to_s + assert_equal "video.mp4", user.highlights.second.filename.to_s + assert_not ActiveStorage::Blob.service.exist?(user.highlights.first.key) + assert_not ActiveStorage::Blob.service.exist?(user.highlights.second.key) + + user.save! + assert user.highlights.first.persisted? + assert user.highlights.second.persisted? + assert user.highlights.first.blob.persisted? + assert user.highlights.second.blob.persisted? + assert_equal "racecar.jpg", user.reload.highlights.first.filename.to_s + assert_equal "video.mp4", user.highlights.second.filename.to_s + assert ActiveStorage::Blob.service.exist?(user.highlights.first.key) + assert ActiveStorage::Blob.service.exist?(user.highlights.second.key) + end + end + + test "creating a record with existing blobs attached" do + user = User.create!(name: "Jason", highlights: [ create_blob(filename: "funky.jpg"), create_blob(filename: "town.jpg") ]) + assert_equal "funky.jpg", user.reload.highlights.first.filename.to_s + assert_equal "town.jpg", user.reload.highlights.second.filename.to_s + end + + test "creating a record with an existing blob from signed IDs attached" do + user = User.create!(name: "Jason", highlights: [ + create_blob(filename: "funky.jpg").signed_id, create_blob(filename: "town.jpg").signed_id ]) + assert_equal "funky.jpg", user.reload.highlights.first.filename.to_s + assert_equal "town.jpg", user.reload.highlights.second.filename.to_s + end + + test "creating a record with new blobs from uploaded files attached" do + User.new(name: "Jason", highlights: [ fixture_file_upload("racecar.jpg"), fixture_file_upload("video.mp4") ]).tap do |user| + assert user.new_record? + assert user.highlights.first.new_record? + assert user.highlights.second.new_record? + assert user.highlights.first.blob.new_record? + assert user.highlights.second.blob.new_record? + assert_equal "racecar.jpg", user.highlights.first.filename.to_s + assert_equal "video.mp4", user.highlights.second.filename.to_s + assert_not ActiveStorage::Blob.service.exist?(user.highlights.first.key) + assert_not ActiveStorage::Blob.service.exist?(user.highlights.second.key) + + user.save! + assert_equal "racecar.jpg", user.highlights.first.filename.to_s + assert_equal "video.mp4", user.highlights.second.filename.to_s + end + end + + test "creating a record with an unexpected object attached" do + error = assert_raises(ArgumentError) { User.create!(name: "Jason", highlights: :foo) } + assert_equal "Could not find or build blob: expected attachable, got :foo", error.message + end + + test "analyzing a new blob from an uploaded file after attaching it to a new record" do + perform_enqueued_jobs do + user = User.create!(name: "Jason", highlights: [ fixture_file_upload("racecar.jpg") ]) + assert user.highlights.reload.first.analyzed? + assert_equal 4104, user.highlights.first.metadata[:width] + assert_equal 2736, user.highlights.first.metadata[:height] + end + end + + test "analyzing a directly-uploaded blob after attaching it to a new record" do + perform_enqueued_jobs do + user = User.create!(name: "Jason", highlights: [ directly_upload_file_blob(filename: "racecar.jpg") ]) + assert user.highlights.reload.first.analyzed? + assert_equal 4104, user.highlights.first.metadata[:width] + assert_equal 2736, user.highlights.first.metadata[:height] + end + end + + test "detaching" do + [ create_blob(filename: "funky.jpg"), create_blob(filename: "town.jpg") ].tap do |blobs| + @user.highlights.attach blobs + assert @user.highlights.attached? + + perform_enqueued_jobs do + @user.highlights.detach + end + + assert_not @user.highlights.attached? + assert ActiveStorage::Blob.exists?(blobs.first.id) + assert ActiveStorage::Blob.exists?(blobs.second.id) + assert ActiveStorage::Blob.service.exist?(blobs.first.key) + assert ActiveStorage::Blob.service.exist?(blobs.second.key) + end + end + + test "purging" do + [ create_blob(filename: "funky.jpg"), create_blob(filename: "town.jpg") ].tap do |blobs| + @user.highlights.attach blobs + assert @user.highlights.attached? + + @user.highlights.purge + assert_not @user.highlights.attached? + assert_not ActiveStorage::Blob.exists?(blobs.first.id) + assert_not ActiveStorage::Blob.exists?(blobs.second.id) + assert_not ActiveStorage::Blob.service.exist?(blobs.first.key) + assert_not ActiveStorage::Blob.service.exist?(blobs.second.key) + end + end + + test "purging later" do + [ create_blob(filename: "funky.jpg"), create_blob(filename: "town.jpg") ].tap do |blobs| + @user.highlights.attach blobs + assert @user.highlights.attached? + + perform_enqueued_jobs do + @user.highlights.purge_later + end + + assert_not @user.highlights.attached? + assert_not ActiveStorage::Blob.exists?(blobs.first.id) + assert_not ActiveStorage::Blob.exists?(blobs.second.id) + assert_not ActiveStorage::Blob.service.exist?(blobs.first.key) + assert_not ActiveStorage::Blob.service.exist?(blobs.second.key) + end + end + + test "purging dependent attachment later on destroy" do + [ create_blob(filename: "funky.jpg"), create_blob(filename: "town.jpg") ].tap do |blobs| + @user.highlights.attach blobs + + perform_enqueued_jobs do + @user.destroy! + end + + assert_not ActiveStorage::Blob.exists?(blobs.first.id) + assert_not ActiveStorage::Blob.exists?(blobs.second.id) + assert_not ActiveStorage::Blob.service.exist?(blobs.first.key) + assert_not ActiveStorage::Blob.service.exist?(blobs.second.key) + end + end + + test "not purging independent attachment on destroy" do + [ create_blob(filename: "funky.mp4"), create_blob(filename: "town.mp4") ].tap do |blobs| + @user.vlogs.attach blobs + + assert_no_enqueued_jobs do + @user.destroy! + end + end + end + + test "clearing change on reload" do + @user.highlights = [ create_blob(filename: "funky.jpg"), create_blob(filename: "town.jpg") ] + assert @user.highlights.attached? + + @user.reload + assert_not @user.highlights.attached? + end + + test "overriding attached reader" do + @user.highlights.attach create_blob(filename: "funky.jpg"), create_blob(filename: "town.jpg") + + assert_equal "funky.jpg", @user.highlights.first.filename.to_s + assert_equal "town.jpg", @user.highlights.second.filename.to_s + + begin + User.class_eval do + def highlights + super.reverse + end + end + + assert_equal "town.jpg", @user.highlights.first.filename.to_s + assert_equal "funky.jpg", @user.highlights.second.filename.to_s + ensure + User.send(:remove_method, :highlights) + end + end +end diff --git a/activestorage/test/models/attached/one_test.rb b/activestorage/test/models/attached/one_test.rb new file mode 100644 index 0000000000..3333fd9323 --- /dev/null +++ b/activestorage/test/models/attached/one_test.rb @@ -0,0 +1,478 @@ +# frozen_string_literal: true + +require "test_helper" +require "database/setup" + +class ActiveStorage::OneAttachedTest < ActiveSupport::TestCase + include ActiveJob::TestHelper + + setup do + @user = User.create!(name: "Josh") + end + + teardown { ActiveStorage::Blob.all.each(&:delete) } + + test "attaching an existing blob to an existing record" do + @user.avatar.attach create_blob(filename: "funky.jpg") + assert_equal "funky.jpg", @user.avatar.filename.to_s + end + + test "attaching an existing blob from a signed ID to an existing record" do + @user.avatar.attach create_blob(filename: "funky.jpg").signed_id + assert_equal "funky.jpg", @user.avatar.filename.to_s + end + + test "attaching a new blob from a Hash to an existing record" do + @user.avatar.attach io: StringIO.new("STUFF"), filename: "town.jpg", content_type: "image/jpg" + assert_equal "town.jpg", @user.avatar.filename.to_s + end + + test "attaching a new blob from an uploaded file to an existing record" do + @user.avatar.attach fixture_file_upload("racecar.jpg") + assert_equal "racecar.jpg", @user.avatar.filename.to_s + end + + test "attaching an existing blob to an existing, changed record" do + @user.name = "Tina" + assert @user.changed? + + @user.avatar.attach create_blob(filename: "funky.jpg") + assert_equal "funky.jpg", @user.avatar.filename.to_s + assert_not @user.avatar.persisted? + assert @user.will_save_change_to_name? + + @user.save! + assert_equal "funky.jpg", @user.reload.avatar.filename.to_s + end + + test "attaching an existing blob from a signed ID to an existing, changed record" do + @user.name = "Tina" + assert @user.changed? + + @user.avatar.attach create_blob(filename: "funky.jpg").signed_id + assert_equal "funky.jpg", @user.avatar.filename.to_s + assert_not @user.avatar.persisted? + assert @user.will_save_change_to_name? + + @user.save! + assert_equal "funky.jpg", @user.reload.avatar.filename.to_s + end + + test "attaching a new blob from a Hash to an existing, changed record" do + @user.name = "Tina" + assert @user.changed? + + @user.avatar.attach io: StringIO.new("STUFF"), filename: "town.jpg", content_type: "image/jpg" + assert_equal "town.jpg", @user.avatar.filename.to_s + assert_not @user.avatar.persisted? + assert @user.will_save_change_to_name? + + @user.save! + assert_equal "town.jpg", @user.reload.avatar.filename.to_s + end + + test "attaching a new blob from an uploaded file to an existing, changed record" do + @user.name = "Tina" + assert @user.changed? + + @user.avatar.attach fixture_file_upload("racecar.jpg") + assert_equal "racecar.jpg", @user.avatar.filename.to_s + assert_not @user.avatar.persisted? + assert @user.will_save_change_to_name? + + @user.save! + assert_equal "racecar.jpg", @user.reload.avatar.filename.to_s + end + + test "updating an existing record to attach an existing blob" do + @user.update! avatar: create_blob(filename: "funky.jpg") + assert_equal "funky.jpg", @user.avatar.filename.to_s + end + + test "updating an existing record to attach an existing blob from a signed ID" do + @user.update! avatar: create_blob(filename: "funky.jpg").signed_id + assert_equal "funky.jpg", @user.avatar.filename.to_s + end + + test "successfully updating an existing record to attach a new blob from an uploaded file" do + @user.avatar = fixture_file_upload("racecar.jpg") + assert_equal "racecar.jpg", @user.avatar.filename.to_s + assert_not ActiveStorage::Blob.service.exist?(@user.avatar.key) + + @user.save! + assert ActiveStorage::Blob.service.exist?(@user.avatar.key) + end + + test "unsuccessfully updating an existing record to attach a new blob from an uploaded file" do + assert_not @user.update(name: "", avatar: fixture_file_upload("racecar.jpg")) + assert_equal "racecar.jpg", @user.avatar.filename.to_s + assert_not ActiveStorage::Blob.service.exist?(@user.avatar.key) + end + + test "successfully replacing an existing, dependent attachment on an existing record" do + create_blob(filename: "funky.jpg").tap do |old_blob| + @user.avatar.attach old_blob + + perform_enqueued_jobs do + @user.avatar.attach create_blob(filename: "town.jpg") + end + + assert_equal "town.jpg", @user.avatar.filename.to_s + assert_not ActiveStorage::Blob.exists?(old_blob.id) + assert_not ActiveStorage::Blob.service.exist?(old_blob.key) + end + end + + test "replacing an existing, independent attachment on an existing record" do + @user.cover_photo.attach create_blob(filename: "funky.jpg") + + assert_no_enqueued_jobs only: ActiveStorage::PurgeJob do + @user.cover_photo.attach create_blob(filename: "town.jpg") + end + + assert_equal "town.jpg", @user.cover_photo.filename.to_s + end + + test "replacing an attached blob on an existing record with itself" do + create_blob(filename: "funky.jpg").tap do |blob| + @user.avatar.attach blob + + assert_no_changes -> { @user.reload.avatar_attachment.id } do + assert_no_enqueued_jobs do + @user.avatar.attach blob + end + end + + assert_equal "funky.jpg", @user.avatar.filename.to_s + assert ActiveStorage::Blob.service.exist?(@user.avatar.key) + end + end + + test "successfully updating an existing record to replace an existing, dependent attachment" do + create_blob(filename: "funky.jpg").tap do |old_blob| + @user.avatar.attach old_blob + + perform_enqueued_jobs do + @user.update! avatar: create_blob(filename: "town.jpg") + end + + assert_equal "town.jpg", @user.avatar.filename.to_s + assert_not ActiveStorage::Blob.exists?(old_blob.id) + assert_not ActiveStorage::Blob.service.exist?(old_blob.key) + end + end + + test "successfully updating an existing record to replace an existing, independent attachment" do + @user.cover_photo.attach create_blob(filename: "funky.jpg") + + assert_no_enqueued_jobs only: ActiveStorage::PurgeJob do + @user.update! cover_photo: create_blob(filename: "town.jpg") + end + + assert_equal "town.jpg", @user.cover_photo.filename.to_s + end + + test "unsuccessfully updating an existing record to replace an existing attachment" do + @user.avatar.attach create_blob(filename: "funky.jpg") + + assert_no_enqueued_jobs do + assert_not @user.update(name: "", avatar: fixture_file_upload("racecar.jpg")) + end + + assert_equal "racecar.jpg", @user.avatar.filename.to_s + assert_not ActiveStorage::Blob.service.exist?(@user.avatar.key) + end + + test "updating an existing record to replace an attached blob with itself" do + create_blob(filename: "funky.jpg").tap do |blob| + @user.avatar.attach blob + + assert_no_enqueued_jobs do + assert_no_changes -> { @user.reload.avatar_attachment.id } do + @user.update! avatar: blob + end + end + end + end + + test "removing a dependent attachment from an existing record" do + create_blob(filename: "funky.jpg").tap do |blob| + @user.avatar.attach blob + + assert_enqueued_with job: ActiveStorage::PurgeJob, args: [ blob ] do + @user.avatar.attach nil + end + + assert_not @user.avatar.attached? + end + end + + test "removing an independent attachment from an existing record" do + create_blob(filename: "funky.jpg").tap do |blob| + @user.cover_photo.attach blob + + assert_no_enqueued_jobs only: ActiveStorage::PurgeJob do + @user.cover_photo.attach nil + end + + assert_not @user.cover_photo.attached? + end + end + + test "updating an existing record to remove a dependent attachment" do + create_blob(filename: "funky.jpg").tap do |blob| + @user.avatar.attach blob + + assert_enqueued_with job: ActiveStorage::PurgeJob, args: [ blob ] do + @user.update! avatar: nil + end + + assert_not @user.avatar.attached? + end + end + + test "updating an existing record to remove an independent attachment" do + create_blob(filename: "funky.jpg").tap do |blob| + @user.cover_photo.attach blob + + assert_no_enqueued_jobs only: ActiveStorage::PurgeJob do + @user.update! cover_photo: nil + end + + assert_not @user.cover_photo.attached? + end + end + + test "analyzing a new blob from an uploaded file after attaching it to an existing record" do + perform_enqueued_jobs do + @user.avatar.attach fixture_file_upload("racecar.jpg") + end + + assert @user.avatar.reload.analyzed? + assert_equal 4104, @user.avatar.metadata[:width] + assert_equal 2736, @user.avatar.metadata[:height] + end + + test "analyzing a new blob from an uploaded file after attaching it to an existing record via update" do + perform_enqueued_jobs do + @user.update! avatar: fixture_file_upload("racecar.jpg") + end + + assert @user.avatar.reload.analyzed? + assert_equal 4104, @user.avatar.metadata[:width] + assert_equal 2736, @user.avatar.metadata[:height] + end + + test "analyzing a directly-uploaded blob after attaching it to an existing record" do + perform_enqueued_jobs do + @user.avatar.attach directly_upload_file_blob(filename: "racecar.jpg") + end + + assert @user.avatar.reload.analyzed? + assert_equal 4104, @user.avatar.metadata[:width] + assert_equal 2736, @user.avatar.metadata[:height] + end + + test "analyzing a directly-uploaded blob after attaching it to an existing record via updates" do + perform_enqueued_jobs do + @user.update! avatar: directly_upload_file_blob(filename: "racecar.jpg") + end + + assert @user.avatar.reload.analyzed? + assert_equal 4104, @user.avatar.metadata[:width] + assert_equal 2736, @user.avatar.metadata[:height] + end + + test "attaching an existing blob to a new record" do + User.new(name: "Jason").tap do |user| + user.avatar.attach create_blob(filename: "funky.jpg") + assert user.new_record? + assert_equal "funky.jpg", user.avatar.filename.to_s + + user.save! + assert_equal "funky.jpg", user.reload.avatar.filename.to_s + end + end + + test "attaching an existing blob from a signed ID to a new record" do + User.new(name: "Jason").tap do |user| + user.avatar.attach create_blob(filename: "funky.jpg").signed_id + assert user.new_record? + assert_equal "funky.jpg", user.avatar.filename.to_s + + user.save! + assert_equal "funky.jpg", user.reload.avatar.filename.to_s + end + end + + test "attaching a new blob from a Hash to a new record" do + User.new(name: "Jason").tap do |user| + user.avatar.attach io: StringIO.new("STUFF"), filename: "town.jpg", content_type: "image/jpg" + assert user.new_record? + assert user.avatar.attachment.new_record? + assert user.avatar.blob.new_record? + assert_equal "town.jpg", user.avatar.filename.to_s + assert_not ActiveStorage::Blob.service.exist?(user.avatar.key) + + user.save! + assert user.avatar.attachment.persisted? + assert user.avatar.blob.persisted? + assert_equal "town.jpg", user.reload.avatar.filename.to_s + assert ActiveStorage::Blob.service.exist?(user.avatar.key) + end + end + + test "attaching a new blob from an uploaded file to a new record" do + User.new(name: "Jason").tap do |user| + user.avatar.attach fixture_file_upload("racecar.jpg") + assert user.new_record? + assert user.avatar.attachment.new_record? + assert user.avatar.blob.new_record? + assert_equal "racecar.jpg", user.avatar.filename.to_s + assert_not ActiveStorage::Blob.service.exist?(user.avatar.key) + + user.save! + assert user.avatar.attachment.persisted? + assert user.avatar.blob.persisted? + assert_equal "racecar.jpg", user.reload.avatar.filename.to_s + assert ActiveStorage::Blob.service.exist?(user.avatar.key) + end + end + + test "creating a record with an existing blob attached" do + user = User.create!(name: "Jason", avatar: create_blob(filename: "funky.jpg")) + assert_equal "funky.jpg", user.reload.avatar.filename.to_s + end + + test "creating a record with an existing blob from a signed ID attached" do + user = User.create!(name: "Jason", avatar: create_blob(filename: "funky.jpg").signed_id) + assert_equal "funky.jpg", user.reload.avatar.filename.to_s + end + + test "creating a record with a new blob from an uploaded file attached" do + User.new(name: "Jason", avatar: fixture_file_upload("racecar.jpg")).tap do |user| + assert user.new_record? + assert user.avatar.attachment.new_record? + assert user.avatar.blob.new_record? + assert_equal "racecar.jpg", user.avatar.filename.to_s + assert_not ActiveStorage::Blob.service.exist?(user.avatar.key) + + user.save! + assert_equal "racecar.jpg", user.reload.avatar.filename.to_s + end + end + + test "creating a record with an unexpected object attached" do + error = assert_raises(ArgumentError) { User.create!(name: "Jason", avatar: :foo) } + assert_equal "Could not find or build blob: expected attachable, got :foo", error.message + end + + test "analyzing a new blob from an uploaded file after attaching it to a new record" do + perform_enqueued_jobs do + user = User.create!(name: "Jason", avatar: fixture_file_upload("racecar.jpg")) + assert user.avatar.reload.analyzed? + assert_equal 4104, user.avatar.metadata[:width] + assert_equal 2736, user.avatar.metadata[:height] + end + end + + test "analyzing a directly-uploaded blob after attaching it to a new record" do + perform_enqueued_jobs do + user = User.create!(name: "Jason", avatar: directly_upload_file_blob(filename: "racecar.jpg")) + assert user.avatar.reload.analyzed? + assert_equal 4104, user.avatar.metadata[:width] + assert_equal 2736, user.avatar.metadata[:height] + end + end + + test "detaching" do + create_blob(filename: "funky.jpg").tap do |blob| + @user.avatar.attach blob + assert @user.avatar.attached? + + perform_enqueued_jobs do + @user.avatar.detach + end + + assert_not @user.avatar.attached? + assert ActiveStorage::Blob.exists?(blob.id) + assert ActiveStorage::Blob.service.exist?(blob.key) + end + end + + test "purging" do + create_blob(filename: "funky.jpg").tap do |blob| + @user.avatar.attach blob + assert @user.avatar.attached? + + @user.avatar.purge + assert_not @user.avatar.attached? + assert_not ActiveStorage::Blob.exists?(blob.id) + assert_not ActiveStorage::Blob.service.exist?(blob.key) + end + end + + test "purging later" do + create_blob(filename: "funky.jpg").tap do |blob| + @user.avatar.attach blob + assert @user.avatar.attached? + + perform_enqueued_jobs do + @user.avatar.purge_later + end + + assert_not @user.avatar.attached? + assert_not ActiveStorage::Blob.exists?(blob.id) + assert_not ActiveStorage::Blob.service.exist?(blob.key) + end + end + + test "purging dependent attachment later on destroy" do + create_blob(filename: "funky.jpg").tap do |blob| + @user.avatar.attach blob + + perform_enqueued_jobs do + @user.destroy! + end + + assert_not ActiveStorage::Blob.exists?(blob.id) + assert_not ActiveStorage::Blob.service.exist?(blob.key) + end + end + + test "not purging independent attachment on destroy" do + create_blob(filename: "funky.jpg").tap do |blob| + @user.cover_photo.attach blob + + assert_no_enqueued_jobs do + @user.destroy! + end + end + end + + test "clearing change on reload" do + @user.avatar = create_blob(filename: "funky.jpg") + assert @user.avatar.attached? + + @user.reload + assert_not @user.avatar.attached? + end + + test "overriding attached reader" do + @user.avatar.attach create_blob(filename: "funky.jpg") + + assert_equal "funky.jpg", @user.avatar.filename.to_s + + begin + User.class_eval do + def avatar + super.filename.to_s.reverse + end + end + + assert_equal "gpj.yknuf", @user.avatar + ensure + User.send(:remove_method, :avatar) + end + end +end diff --git a/activestorage/test/models/attached_test.rb b/activestorage/test/models/attached_test.rb deleted file mode 100644 index 14395e12df..0000000000 --- a/activestorage/test/models/attached_test.rb +++ /dev/null @@ -1,54 +0,0 @@ -# frozen_string_literal: true - -require "test_helper" -require "database/setup" - -class ActiveStorage::AttachmentsTest < ActiveSupport::TestCase - include ActiveJob::TestHelper - - setup do - @user = User.create!(name: "Josh") - end - - teardown { ActiveStorage::Blob.all.each(&:purge) } - - test "overriding has_one_attached methods works" do - # attach blob before messing with getter, which breaks `#attach` - @user.avatar.attach create_blob(filename: "funky.jpg") - - # inherited only - assert_equal "funky.jpg", @user.avatar.filename.to_s - - User.class_eval do - def avatar - super.filename.to_s.reverse - end - end - - # override with super - assert_equal "funky.jpg".reverse, @user.avatar - - User.send(:remove_method, :avatar) - end - - test "overriding has_many_attached methods works" do - # attach blobs before messing with getter, which breaks `#attach` - @user.highlights.attach create_blob(filename: "funky.jpg"), create_blob(filename: "wonky.jpg") - - # inherited only - assert_equal "funky.jpg", @user.highlights.first.filename.to_s - assert_equal "wonky.jpg", @user.highlights.second.filename.to_s - - User.class_eval do - def highlights - super.reverse - end - end - - # override with super - assert_equal "wonky.jpg", @user.highlights.first.filename.to_s - assert_equal "funky.jpg", @user.highlights.second.filename.to_s - - User.send(:remove_method, :highlights) - end -end diff --git a/activestorage/test/models/attachments_test.rb b/activestorage/test/models/attachments_test.rb deleted file mode 100644 index ce83ec27d2..0000000000 --- a/activestorage/test/models/attachments_test.rb +++ /dev/null @@ -1,459 +0,0 @@ -# frozen_string_literal: true - -require "test_helper" -require "database/setup" - -class ActiveStorage::AttachmentsTest < ActiveSupport::TestCase - include ActiveJob::TestHelper - - setup { @user = User.create!(name: "DHH") } - - teardown { ActiveStorage::Blob.all.each(&:purge) } - - test "attach existing blob" do - @user.avatar.attach create_blob(filename: "funky.jpg") - assert_equal "funky.jpg", @user.avatar.filename.to_s - end - - test "attach existing blob from a signed ID" do - @user.avatar.attach create_blob(filename: "funky.jpg").signed_id - assert_equal "funky.jpg", @user.avatar.filename.to_s - end - - test "attach new blob from a Hash" do - @user.avatar.attach io: StringIO.new("STUFF"), filename: "town.jpg", content_type: "image/jpg" - assert_equal "town.jpg", @user.avatar.filename.to_s - end - - test "attach new blob from an UploadedFile" do - file = file_fixture "racecar.jpg" - @user.avatar.attach Rack::Test::UploadedFile.new file.to_s - assert_equal "racecar.jpg", @user.avatar.filename.to_s - end - - test "replace attached blob" do - @user.avatar.attach create_blob(filename: "funky.jpg") - - perform_enqueued_jobs do - assert_no_difference -> { ActiveStorage::Blob.count } do - @user.avatar.attach create_blob(filename: "town.jpg") - end - end - - assert_equal "town.jpg", @user.avatar.filename.to_s - end - - test "replace attached blob unsuccessfully" do - @user.avatar.attach create_blob(filename: "funky.jpg") - - perform_enqueued_jobs do - assert_raises do - @user.avatar.attach nil - end - end - - assert_equal "funky.jpg", @user.reload.avatar.filename.to_s - assert ActiveStorage::Blob.service.exist?(@user.avatar.key) - end - - test "replace attached blob with itself" do - @user.avatar.attach create_blob(filename: "funky.jpg") - - assert_no_changes -> { @user.reload.avatar.blob } do - assert_no_changes -> { @user.reload.avatar.attachment } do - assert_no_enqueued_jobs do - @user.avatar.attach @user.avatar.blob - end - end - end - end - - test "replaced attached blob with itself by signed ID" do - @user.avatar.attach create_blob(filename: "funky.jpg") - - assert_no_changes -> { @user.reload.avatar.blob } do - assert_no_changes -> { @user.reload.avatar.attachment } do - assert_no_enqueued_jobs do - @user.avatar.attach @user.avatar.blob.signed_id - end - end - end - end - - test "replace independent attached blob" do - @user.cover_photo.attach create_blob(filename: "funky.jpg") - - perform_enqueued_jobs do - assert_difference -> { ActiveStorage::Blob.count }, +1 do - assert_no_difference -> { ActiveStorage::Attachment.count } do - @user.cover_photo.attach create_blob(filename: "town.jpg") - end - end - end - - assert_equal "town.jpg", @user.cover_photo.filename.to_s - end - - test "attach blob to new record" do - user = User.new(name: "Jason") - - assert_no_changes -> { user.new_record? } do - assert_no_difference -> { ActiveStorage::Attachment.count } do - user.avatar.attach create_blob(filename: "funky.jpg") - end - end - - assert_predicate user.avatar, :attached? - assert_equal "funky.jpg", user.avatar.filename.to_s - - assert_difference -> { ActiveStorage::Attachment.count }, +1 do - user.save! - end - - assert_predicate user.reload.avatar, :attached? - assert_equal "funky.jpg", user.avatar.filename.to_s - end - - test "build new record with attached blob" do - assert_no_difference -> { ActiveStorage::Attachment.count } do - @user = User.new(name: "Jason", avatar: { io: StringIO.new("STUFF"), filename: "town.jpg", content_type: "image/jpg" }) - end - - assert_predicate @user, :new_record? - assert_predicate @user.avatar, :attached? - assert_equal "town.jpg", @user.avatar.filename.to_s - - @user.save! - assert_predicate @user.reload.avatar, :attached? - assert_equal "town.jpg", @user.avatar.filename.to_s - end - - test "access underlying associations of new blob" do - @user.avatar.attach create_blob(filename: "funky.jpg") - assert_equal @user, @user.avatar_attachment.record - assert_equal @user.avatar_attachment.blob, @user.avatar_blob - assert_equal "funky.jpg", @user.avatar_attachment.blob.filename.to_s - end - - test "identify newly-attached, directly-uploaded blob" do - blob = directly_upload_file_blob(content_type: "application/octet-stream") - - @user.avatar.attach(blob) - - assert_equal "image/jpeg", @user.avatar.reload.content_type - assert_predicate @user.avatar, :identified? - end - - test "identify and analyze newly-attached, directly-uploaded blob" do - blob = directly_upload_file_blob(content_type: "application/octet-stream") - - perform_enqueued_jobs do - @user.avatar.attach blob - end - - assert_equal true, @user.avatar.reload.metadata[:identified] - assert_equal 4104, @user.avatar.metadata[:width] - assert_equal 2736, @user.avatar.metadata[:height] - end - - test "identify newly-attached blob only once" do - blob = create_file_blob - assert_predicate blob, :identified? - - # The blob's backing file is a PNG image. Fudge its content type so we can tell if it's identified when we attach it. - blob.update! content_type: "application/octet-stream" - - @user.avatar.attach blob - assert_equal "application/octet-stream", blob.content_type - end - - test "analyze newly-attached blob" do - perform_enqueued_jobs do - @user.avatar.attach create_file_blob - end - - assert_equal 4104, @user.avatar.reload.metadata[:width] - assert_equal 2736, @user.avatar.metadata[:height] - end - - test "analyze attached blob only once" do - blob = create_file_blob - - perform_enqueued_jobs do - @user.avatar.attach blob - end - - assert_predicate blob.reload, :analyzed? - - @user.avatar.detach - - assert_no_enqueued_jobs do - @user.reload.avatar.attach blob - end - end - - test "preserve existing metadata when analyzing a newly-attached blob" do - blob = create_file_blob(metadata: { foo: "bar" }) - - perform_enqueued_jobs do - @user.avatar.attach blob - end - - assert_equal "bar", blob.reload.metadata[:foo] - end - - test "detach blob" do - @user.avatar.attach create_blob(filename: "funky.jpg") - avatar_blob_id = @user.avatar.blob.id - avatar_key = @user.avatar.key - - @user.avatar.detach - assert_not_predicate @user.avatar, :attached? - assert ActiveStorage::Blob.exists?(avatar_blob_id) - assert ActiveStorage::Blob.service.exist?(avatar_key) - end - - test "purge attached blob" do - @user.avatar.attach create_blob(filename: "funky.jpg") - avatar_key = @user.avatar.key - - @user.avatar.purge - assert_not_predicate @user.avatar, :attached? - assert_not ActiveStorage::Blob.service.exist?(avatar_key) - end - - test "purge attached blob later when the record is destroyed" do - @user.avatar.attach create_blob(filename: "funky.jpg") - avatar_key = @user.avatar.key - - perform_enqueued_jobs do - @user.reload.destroy - - assert_nil ActiveStorage::Blob.find_by(key: avatar_key) - assert_not ActiveStorage::Blob.service.exist?(avatar_key) - end - end - - test "delete attachment for independent blob when record is destroyed" do - @user.cover_photo.attach create_blob(filename: "funky.jpg") - - @user.destroy - assert_not ActiveStorage::Attachment.exists?(record: @user, name: "cover_photo") - end - - test "find with attached blob" do - records = %w[alice bob].map do |name| - User.create!(name: name).tap do |user| - user.avatar.attach create_blob(filename: "#{name}.jpg") - end - end - - users = User.where(id: records.map(&:id)).with_attached_avatar.all - - assert_equal "alice.jpg", users.first.avatar.filename.to_s - assert_equal "bob.jpg", users.second.avatar.filename.to_s - end - - - test "attach existing blobs" do - @user.highlights.attach create_blob(filename: "funky.jpg"), create_blob(filename: "wonky.jpg") - - assert_equal "funky.jpg", @user.highlights.first.filename.to_s - assert_equal "wonky.jpg", @user.highlights.second.filename.to_s - end - - test "attach new blobs" do - @user.highlights.attach( - { io: StringIO.new("STUFF"), filename: "town.jpg", content_type: "image/jpg" }, - { io: StringIO.new("IT"), filename: "country.jpg", content_type: "image/jpg" }) - - assert_equal "town.jpg", @user.highlights.first.filename.to_s - assert_equal "country.jpg", @user.highlights.second.filename.to_s - end - - test "attach blobs to new record" do - user = User.new(name: "Jason") - - assert_no_changes -> { user.new_record? } do - assert_no_difference -> { ActiveStorage::Attachment.count } do - user.highlights.attach( - { io: StringIO.new("STUFF"), filename: "town.jpg", content_type: "image/jpg" }, - { io: StringIO.new("IT"), filename: "country.jpg", content_type: "image/jpg" }) - end - end - - assert_predicate user.highlights, :attached? - assert_equal "town.jpg", user.highlights.first.filename.to_s - assert_equal "country.jpg", user.highlights.second.filename.to_s - - assert_difference -> { ActiveStorage::Attachment.count }, +2 do - user.save! - end - - assert_predicate user.reload.highlights, :attached? - assert_equal "town.jpg", user.highlights.first.filename.to_s - assert_equal "country.jpg", user.highlights.second.filename.to_s - end - - test "build new record with attached blobs" do - assert_no_difference -> { ActiveStorage::Attachment.count } do - @user = User.new(name: "Jason", highlights: [ - { io: StringIO.new("STUFF"), filename: "town.jpg", content_type: "image/jpg" }, - { io: StringIO.new("IT"), filename: "country.jpg", content_type: "image/jpg" }]) - end - - assert_predicate @user, :new_record? - assert_predicate @user.highlights, :attached? - assert_equal "town.jpg", @user.highlights.first.filename.to_s - assert_equal "country.jpg", @user.highlights.second.filename.to_s - - @user.save! - assert_predicate @user.reload.highlights, :attached? - assert_equal "town.jpg", @user.highlights.first.filename.to_s - assert_equal "country.jpg", @user.highlights.second.filename.to_s - end - - test "find attached blobs" do - @user.highlights.attach( - { io: StringIO.new("STUFF"), filename: "town.jpg", content_type: "image/jpg" }, - { io: StringIO.new("IT"), filename: "country.jpg", content_type: "image/jpg" }) - - highlights = User.where(id: @user.id).with_attached_highlights.first.highlights - - assert_equal "town.jpg", highlights.first.filename.to_s - assert_equal "country.jpg", highlights.second.filename.to_s - end - - test "access underlying associations of new blobs" do - @user.highlights.attach( - { io: StringIO.new("STUFF"), filename: "town.jpg", content_type: "image/jpg" }, - { io: StringIO.new("IT"), filename: "country.jpg", content_type: "image/jpg" }) - - assert_equal @user, @user.highlights_attachments.first.record - assert_equal @user.highlights_attachments.collect(&:blob).sort, @user.highlights_blobs.sort - assert_equal "town.jpg", @user.highlights_attachments.first.blob.filename.to_s - end - - test "analyze newly-attached blobs" do - perform_enqueued_jobs do - @user.highlights.attach( - create_file_blob(filename: "racecar.jpg", content_type: "image/jpeg"), - create_file_blob(filename: "video.mp4", content_type: "video/mp4")) - end - - assert_equal 4104, @user.highlights.first.metadata[:width] - assert_equal 2736, @user.highlights.first.metadata[:height] - - assert_equal 640, @user.highlights.second.metadata[:width] - assert_equal 480, @user.highlights.second.metadata[:height] - end - - test "analyze attached blobs only once" do - blobs = [ - create_file_blob(filename: "racecar.jpg", content_type: "image/jpeg"), - create_file_blob(filename: "video.mp4", content_type: "video/mp4") - ] - - perform_enqueued_jobs do - @user.highlights.attach(blobs) - end - - assert blobs.each(&:reload).all?(&:analyzed?) - - @user.highlights.attachments.destroy_all - - assert_no_enqueued_jobs do - @user.highlights.attach(blobs) - end - end - - test "preserve existing metadata when analyzing newly-attached blobs" do - blobs = [ - create_file_blob(filename: "racecar.jpg", content_type: "image/jpeg", metadata: { foo: "bar" }), - create_file_blob(filename: "video.mp4", content_type: "video/mp4", metadata: { foo: "bar" }) - ] - - perform_enqueued_jobs do - @user.highlights.attach(blobs) - end - - blobs.each do |blob| - assert_equal "bar", blob.reload.metadata[:foo] - end - end - - test "detach blobs" do - @user.highlights.attach create_blob(filename: "funky.jpg"), create_blob(filename: "wonky.jpg") - highlight_blob_ids = @user.highlights.collect { |highlight| highlight.blob.id } - highlight_keys = @user.highlights.collect(&:key) - - @user.highlights.detach - assert_not_predicate @user.highlights, :attached? - - assert ActiveStorage::Blob.exists?(highlight_blob_ids.first) - assert ActiveStorage::Blob.exists?(highlight_blob_ids.second) - - assert ActiveStorage::Blob.service.exist?(highlight_keys.first) - assert ActiveStorage::Blob.service.exist?(highlight_keys.second) - end - - test "purge attached blobs" do - @user.highlights.attach create_blob(filename: "funky.jpg"), create_blob(filename: "wonky.jpg") - highlight_keys = @user.highlights.collect(&:key) - - @user.highlights.purge - assert_not_predicate @user.highlights, :attached? - assert_not ActiveStorage::Blob.service.exist?(highlight_keys.first) - assert_not ActiveStorage::Blob.service.exist?(highlight_keys.second) - end - - test "purge attached blobs later when the record is destroyed" do - @user.highlights.attach create_blob(filename: "funky.jpg"), create_blob(filename: "wonky.jpg") - highlight_keys = @user.highlights.collect(&:key) - - perform_enqueued_jobs do - @user.reload.destroy - - assert_nil ActiveStorage::Blob.find_by(key: highlight_keys.first) - assert_not ActiveStorage::Blob.service.exist?(highlight_keys.first) - - assert_nil ActiveStorage::Blob.find_by(key: highlight_keys.second) - assert_not ActiveStorage::Blob.service.exist?(highlight_keys.second) - end - end - - test "delete attachments for independent blobs when the record is destroyed" do - @user.vlogs.attach create_blob(filename: "funky.mp4"), create_blob(filename: "wonky.mp4") - - @user.destroy - assert_not ActiveStorage::Attachment.exists?(record: @user, name: "vlogs") - end - - test "selectively purge one attached blob of many" do - first_blob = create_blob(filename: "funky.jpg") - second_blob = create_blob(filename: "wonky.jpg") - attachments = @user.highlights.attach(first_blob, second_blob) - - assert_difference -> { ActiveStorage::Blob.count }, -1 do - @user.highlights.where(id: attachments.first.id).purge - end - - assert_not ActiveStorage::Blob.exists?(key: first_blob.key) - assert ActiveStorage::Blob.exists?(key: second_blob.key) - end - - test "selectively purge one attached blob of many later" do - first_blob = create_blob(filename: "funky.jpg") - second_blob = create_blob(filename: "wonky.jpg") - attachments = @user.highlights.attach(first_blob, second_blob) - - perform_enqueued_jobs do - assert_difference -> { ActiveStorage::Blob.count }, -1 do - @user.highlights.where(id: attachments.first.id).purge_later - end - end - - assert_not ActiveStorage::Blob.exists?(key: first_blob.key) - assert ActiveStorage::Blob.exists?(key: second_blob.key) - end -end diff --git a/activestorage/test/models/blob_test.rb b/activestorage/test/models/blob_test.rb index a013b7a924..c2e7aae13a 100644 --- a/activestorage/test/models/blob_test.rb +++ b/activestorage/test/models/blob_test.rb @@ -7,21 +7,15 @@ require "active_support/testing/method_call_assertions" class ActiveStorage::BlobTest < ActiveSupport::TestCase include ActiveSupport::Testing::MethodCallAssertions - test ".unattached scope returns not attached blobs" do - class UserWithHasOneAttachedDependentFalse < User - has_one_attached :avatar, dependent: false + test "unattached scope" do + [ create_blob(filename: "funky.jpg"), create_blob(filename: "town.jpg") ].tap do |blobs| + User.create! name: "DHH", avatar: blobs.first + assert_includes ActiveStorage::Blob.unattached, blobs.second + assert_not_includes ActiveStorage::Blob.unattached, blobs.first + + User.create! name: "Jason", avatar: blobs.second + assert_not_includes ActiveStorage::Blob.unattached, blobs.second end - - ActiveStorage::Blob.delete_all - blob_1 = create_blob filename: "funky.jpg" - blob_2 = create_blob filename: "town.jpg" - - user = UserWithHasOneAttachedDependentFalse.create! - user.avatar.attach blob_1 - - assert_equal [blob_2], ActiveStorage::Blob.unattached - user.destroy - assert_equal [blob_1, blob_2].map(&:id).sort, ActiveStorage::Blob.unattached.pluck(:id).sort end test "create after upload sets byte size and checksum" do @@ -84,12 +78,25 @@ class ActiveStorage::BlobTest < ActiveSupport::TestCase assert_equal "a" * 64.kilobytes, chunks.second end - test "open" 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" + test "open with integrity" do + 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 + + test "open without integrity" do + create_blob(data: "Hello, world!").tap do |blob| + blob.update! checksum: Digest::MD5.base64digest("Goodbye, world!") + + assert_raises ActiveStorage::IntegrityError do + blob.open { |file| flunk "Expected integrity check to fail" } + end end end @@ -138,16 +145,16 @@ class ActiveStorage::BlobTest < ActiveSupport::TestCase test "urls allow for custom options" do blob = create_blob(filename: "original.txt") - options = [ + arguments = [ blob.key, - expires_in: blob.service.url_expires_in, + expires_in: ActiveStorage.service_urls_expire_in, disposition: :inline, content_type: blob.content_type, filename: blob.filename, thumb_size: "300x300", thumb_mode: "crop" ] - assert_called_with(blob.service, :url, options) do + assert_called_with(blob.service, :url, arguments) do blob.service_url(thumb_size: "300x300", thumb_mode: "crop") end end @@ -167,6 +174,14 @@ class ActiveStorage::BlobTest < ActiveSupport::TestCase assert_not ActiveStorage::Blob.service.exist?(variant.key) end + test "purge fails when attachments exist" do + create_blob.tap do |blob| + User.create! name: "DHH", avatar: blob + assert_raises(ActiveRecord::InvalidForeignKey) { blob.purge } + assert ActiveStorage::Blob.service.exist?(blob.key) + end + end + private def expected_url_for(blob, disposition: :inline, filename: nil) filename ||= blob.filename diff --git a/activestorage/test/models/presence_validation_test.rb b/activestorage/test/models/presence_validation_test.rb index aa804506dd..13ba3c900d 100644 --- a/activestorage/test/models/presence_validation_test.rb +++ b/activestorage/test/models/presence_validation_test.rb @@ -12,7 +12,7 @@ class ActiveStorage::PresenceValidationTest < ActiveSupport::TestCase test "validates_presence_of has_one_attached" do Admin.validates_presence_of :avatar - a = Admin.new + a = Admin.new(name: "DHH") assert_predicate a, :invalid? a.avatar.attach create_blob(filename: "funky.jpg") @@ -21,7 +21,7 @@ class ActiveStorage::PresenceValidationTest < ActiveSupport::TestCase test "validates_presence_of has_many_attached" do Admin.validates_presence_of :highlights - a = Admin.new + a = Admin.new(name: "DHH") assert_predicate a, :invalid? a.highlights.attach create_blob(filename: "funky.jpg") diff --git a/activestorage/test/models/reflection_test.rb b/activestorage/test/models/reflection_test.rb new file mode 100644 index 0000000000..98606b0617 --- /dev/null +++ b/activestorage/test/models/reflection_test.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +require "test_helper" + +class ActiveStorage::ReflectionTest < ActiveSupport::TestCase + test "reflecting on a singular attachment" do + reflection = User.reflect_on_attachment(:avatar) + assert_equal User, reflection.active_record + assert_equal :avatar, reflection.name + assert_equal :has_one_attached, reflection.macro + assert_equal :purge_later, reflection.options[:dependent] + end + + test "reflection on a singular attachment with the same name as an attachment on another model" do + reflection = Group.reflect_on_attachment(:avatar) + assert_equal Group, reflection.active_record + end + + test "reflecting on a collection attachment" do + reflection = User.reflect_on_attachment(:highlights) + assert_equal User, reflection.active_record + assert_equal :highlights, reflection.name + assert_equal :has_many_attached, reflection.macro + assert_equal :purge_later, reflection.options[:dependent] + end + + test "reflecting on all attachments" do + reflections = User.reflect_on_all_attachments.sort_by(&:name) + assert_equal [ User ], reflections.collect(&:active_record).uniq + assert_equal %i[ avatar cover_photo highlights vlogs ], reflections.collect(&:name) + assert_equal %i[ has_one_attached has_one_attached has_many_attached has_many_attached ], reflections.collect(&:macro) + assert_equal [ :purge_later, false, :purge_later, false ], reflections.collect { |reflection| reflection.options[:dependent] } + end +end diff --git a/activestorage/test/service/azure_storage_service_test.rb b/activestorage/test/service/azure_storage_service_test.rb index be31bbe858..76920850d1 100644 --- a/activestorage/test/service/azure_storage_service_test.rb +++ b/activestorage/test/service/azure_storage_service_test.rb @@ -10,7 +10,7 @@ if SERVICE_CONFIGURATIONS[:azure] include ActiveStorage::Service::SharedServiceTests test "signed URL generation" do - url = @service.url(FIXTURE_KEY, expires_in: 5.minutes, + url = @service.url(@key, expires_in: 5.minutes, disposition: :inline, filename: ActiveStorage::Filename.new("avatar.png"), content_type: "image/png") assert_match(/(\S+)&rscd=inline%3B\+filename%3D%22avatar\.png%22%3B\+filename\*%3DUTF-8%27%27avatar\.png&rsct=image%2Fpng/, url) diff --git a/activestorage/test/service/disk_service_test.rb b/activestorage/test/service/disk_service_test.rb index a4f2f4765f..a0218bff1c 100644 --- a/activestorage/test/service/disk_service_test.rb +++ b/activestorage/test/service/disk_service_test.rb @@ -9,10 +9,10 @@ class ActiveStorage::Service::DiskServiceTest < ActiveSupport::TestCase test "url generation" do assert_match(/^https:\/\/example.com\/rails\/active_storage\/disk\/.*\/avatar\.png\?content_type=image%2Fpng&disposition=inline/, - @service.url(FIXTURE_KEY, expires_in: 5.minutes, disposition: :inline, filename: ActiveStorage::Filename.new("avatar.png"), content_type: "image/png")) + @service.url(@key, expires_in: 5.minutes, disposition: :inline, filename: ActiveStorage::Filename.new("avatar.png"), content_type: "image/png")) end test "headers_for_direct_upload generation" do - assert_equal({ "Content-Type" => "application/json" }, @service.headers_for_direct_upload(FIXTURE_KEY, content_type: "application/json")) + assert_equal({ "Content-Type" => "application/json" }, @service.headers_for_direct_upload(@key, content_type: "application/json")) end end diff --git a/activestorage/test/service/gcs_service_test.rb b/activestorage/test/service/gcs_service_test.rb index fc2d9d0fa7..2ba2f8b346 100644 --- a/activestorage/test/service/gcs_service_test.rb +++ b/activestorage/test/service/gcs_service_test.rb @@ -33,7 +33,7 @@ if SERVICE_CONFIGURATIONS[:gcs] test "signed URL generation" do assert_match(/storage\.googleapis\.com\/.*response-content-disposition=inline.*test\.txt.*response-content-type=text%2Fplain/, - @service.url(FIXTURE_KEY, expires_in: 2.minutes, disposition: :inline, filename: ActiveStorage::Filename.new("test.txt"), content_type: "text/plain")) + @service.url(@key, expires_in: 2.minutes, disposition: :inline, filename: ActiveStorage::Filename.new("test.txt"), content_type: "text/plain")) end test "signed URL response headers" do @@ -44,7 +44,7 @@ if SERVICE_CONFIGURATIONS[:gcs] url = @service.url(key, expires_in: 2.minutes, disposition: :inline, filename: ActiveStorage::Filename.new("test.txt"), content_type: "text/plain") response = Net::HTTP.get_response(URI(url)) - assert_equal "text/plain", response.header["Content-Type"] + assert_equal "text/plain", response.content_type ensure @service.delete key end diff --git a/activestorage/test/service/mirror_service_test.rb b/activestorage/test/service/mirror_service_test.rb index 87306644c5..bb502dde60 100644 --- a/activestorage/test/service/mirror_service_test.rb +++ b/activestorage/test/service/mirror_service_test.rb @@ -47,11 +47,11 @@ class ActiveStorage::Service::MirrorServiceTest < ActiveSupport::TestCase end test "deleting from all services" do - @service.delete FIXTURE_KEY + @service.delete @key - assert_not SERVICE.primary.exist?(FIXTURE_KEY) + assert_not SERVICE.primary.exist?(@key) SERVICE.mirrors.each do |mirror| - assert_not mirror.exist?(FIXTURE_KEY) + assert_not mirror.exist?(@key) end end @@ -59,8 +59,8 @@ class ActiveStorage::Service::MirrorServiceTest < ActiveSupport::TestCase filename = ActiveStorage::Filename.new("test.txt") freeze_time do - assert_equal @service.primary.url(FIXTURE_KEY, expires_in: 2.minutes, disposition: :inline, filename: filename, content_type: "text/plain"), - @service.url(FIXTURE_KEY, expires_in: 2.minutes, disposition: :inline, filename: filename, content_type: "text/plain") + assert_equal @service.primary.url(@key, expires_in: 2.minutes, disposition: :inline, filename: filename, content_type: "text/plain"), + @service.url(@key, expires_in: 2.minutes, disposition: :inline, filename: filename, content_type: "text/plain") end end end diff --git a/activestorage/test/service/s3_service_test.rb b/activestorage/test/service/s3_service_test.rb index 7833e51122..4bfcda017f 100644 --- a/activestorage/test/service/s3_service_test.rb +++ b/activestorage/test/service/s3_service_test.rb @@ -32,7 +32,7 @@ if SERVICE_CONFIGURATIONS[:s3] end test "signed URL generation" do - url = @service.url(FIXTURE_KEY, expires_in: 5.minutes, + url = @service.url(@key, expires_in: 5.minutes, disposition: :inline, filename: ActiveStorage::Filename.new("avatar.png"), content_type: "image/png") assert_match(/s3(-[-a-z0-9]+)?\.(\S+)?amazonaws.com.*response-content-disposition=inline.*avatar\.png.*response-content-type=image%2Fpng/, url) diff --git a/activestorage/test/service/shared_service_tests.rb b/activestorage/test/service/shared_service_tests.rb index b9f352e460..30cfca4e36 100644 --- a/activestorage/test/service/shared_service_tests.rb +++ b/activestorage/test/service/shared_service_tests.rb @@ -6,17 +6,17 @@ require "active_support/core_ext/securerandom" module ActiveStorage::Service::SharedServiceTests extend ActiveSupport::Concern - FIXTURE_KEY = SecureRandom.base58(24) FIXTURE_DATA = "\211PNG\r\n\032\n\000\000\000\rIHDR\000\000\000\020\000\000\000\020\001\003\000\000\000%=m\"\000\000\000\006PLTE\000\000\000\377\377\377\245\331\237\335\000\000\0003IDATx\234c\370\377\237\341\377_\206\377\237\031\016\2603\334?\314p\1772\303\315\315\f7\215\031\356\024\203\320\275\317\f\367\201R\314\f\017\300\350\377\177\000Q\206\027(\316]\233P\000\000\000\000IEND\256B`\202".dup.force_encoding(Encoding::BINARY) included do setup do + @key = SecureRandom.base58(24) @service = self.class.const_get(:SERVICE) - @service.upload FIXTURE_KEY, StringIO.new(FIXTURE_DATA) + @service.upload @key, StringIO.new(FIXTURE_DATA) end teardown do - @service.delete FIXTURE_KEY + @service.delete @key end test "uploading with integrity" do @@ -47,7 +47,7 @@ module ActiveStorage::Service::SharedServiceTests end test "downloading" do - assert_equal FIXTURE_DATA, @service.download(FIXTURE_KEY) + assert_equal FIXTURE_DATA, @service.download(@key) end test "downloading in chunks" do @@ -69,18 +69,18 @@ module ActiveStorage::Service::SharedServiceTests end test "downloading partially" do - assert_equal "\x10\x00\x00", @service.download_chunk(FIXTURE_KEY, 19..21) - assert_equal "\x10\x00\x00", @service.download_chunk(FIXTURE_KEY, 19...22) + assert_equal "\x10\x00\x00", @service.download_chunk(@key, 19..21) + assert_equal "\x10\x00\x00", @service.download_chunk(@key, 19...22) end test "existing" do - assert @service.exist?(FIXTURE_KEY) - assert_not @service.exist?(FIXTURE_KEY + "nonsense") + assert @service.exist?(@key) + assert_not @service.exist?(@key + "nonsense") end test "deleting" do - @service.delete FIXTURE_KEY - assert_not @service.exist?(FIXTURE_KEY) + @service.delete @key + assert_not @service.exist?(@key) end test "deleting nonexistent key" do diff --git a/activestorage/test/test_helper.rb b/activestorage/test/test_helper.rb index 573a8e0b0b..7b7926ac79 100644 --- a/activestorage/test/test_helper.rb +++ b/activestorage/test/test_helper.rb @@ -79,6 +79,10 @@ class ActiveSupport::TestCase def extract_metadata_from(blob) blob.tap(&:analyze).metadata end + + def fixture_file_upload(filename) + Rack::Test::UploadedFile.new file_fixture(filename).to_s + end end require "global_id" @@ -86,9 +90,15 @@ GlobalID.app = "ActiveStorageExampleApp" ActiveRecord::Base.send :include, GlobalID::Identification class User < ActiveRecord::Base + validates :name, presence: true + has_one_attached :avatar has_one_attached :cover_photo, dependent: false has_many_attached :highlights has_many_attached :vlogs, dependent: false end + +class Group < ActiveRecord::Base + has_one_attached :avatar +end diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md index 91818c3112..24ad72c45d 100644 --- a/activesupport/CHANGELOG.md +++ b/activesupport/CHANGELOG.md @@ -1,3 +1,13 @@ +* RedisCacheStore: support key expiry in increment/decrement. + + Pass `:expires_in` to `#increment` and `#decrement` to set a Redis EXPIRE on the key. + + If the key is already set to expire, RedisCacheStore won't extend its expiry. + + Rails.cache.increment("some_key", 1, expires_in: 2.minutes) + + *Jason Lee* + * Allow Range#=== and Range#cover? on Range `Range#cover?` can now accept a range argument like `Range#include?` and @@ -20,7 +30,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/cache/redis_cache_store.rb b/activesupport/lib/active_support/cache/redis_cache_store.rb index 11c574258f..5737450b4a 100644 --- a/activesupport/lib/active_support/cache/redis_cache_store.rb +++ b/activesupport/lib/active_support/cache/redis_cache_store.rb @@ -258,7 +258,14 @@ module ActiveSupport def increment(name, amount = 1, options = nil) instrument :increment, name, amount: amount do failsafe :increment do - redis.with { |c| c.incrby normalize_key(name, options), amount } + options = merged_options(options) + key = normalize_key(name, options) + + redis.with do |c| + c.incrby(key, amount).tap do + write_key_expiry(c, key, options) + end + end end end end @@ -274,7 +281,14 @@ module ActiveSupport def decrement(name, amount = 1, options = nil) instrument :decrement, name, amount: amount do failsafe :decrement do - redis.with { |c| c.decrby normalize_key(name, options), amount } + options = merged_options(options) + key = normalize_key(name, options) + + redis.with do |c| + c.decrby(key, amount).tap do + write_key_expiry(c, key, options) + end + end end end end @@ -385,6 +399,12 @@ module ActiveSupport end end + def write_key_expiry(client, key, options) + if options[:expires_in] && client.ttl(key).negative? + client.expire key, options[:expires_in].to_i + end + end + # Delete an entry from the cache. def delete_entry(key, options) failsafe :delete_entry, returning: false do diff --git a/activesupport/lib/active_support/core_ext/date_and_time/calculations.rb b/activesupport/lib/active_support/core_ext/date_and_time/calculations.rb index 976a10d0f5..05abd83221 100644 --- a/activesupport/lib/active_support/core_ext/date_and_time/calculations.rb +++ b/activesupport/lib/active_support/core_ext/date_and_time/calculations.rb @@ -5,13 +5,13 @@ require "active_support/core_ext/object/try" module DateAndTime module Calculations DAYS_INTO_WEEK = { - monday: 0, - tuesday: 1, - wednesday: 2, - thursday: 3, - friday: 4, - saturday: 5, - sunday: 6 + sunday: 0, + monday: 1, + tuesday: 2, + wednesday: 3, + thursday: 4, + friday: 5, + saturday: 6 } WEEKEND_DAYS = [ 6, 0 ] @@ -263,9 +263,8 @@ module DateAndTime # Week is assumed to start on +start_day+, default is # +Date.beginning_of_week+ or +config.beginning_of_week+ when set. def days_to_week_start(start_day = Date.beginning_of_week) - start_day_number = DAYS_INTO_WEEK[start_day] - current_day_number = wday != 0 ? wday - 1 : 6 - (current_day_number - start_day_number) % 7 + start_day_number = DAYS_INTO_WEEK.fetch(start_day) + (wday - start_day_number) % 7 end # Returns a new date/time representing the start of this week on the given day. @@ -346,8 +345,7 @@ module DateAndTime # today.next_occurring(:monday) # => Mon, 18 Dec 2017 # today.next_occurring(:thursday) # => Thu, 21 Dec 2017 def next_occurring(day_of_week) - current_day_number = wday != 0 ? wday - 1 : 6 - from_now = DAYS_INTO_WEEK.fetch(day_of_week) - current_day_number + from_now = DAYS_INTO_WEEK.fetch(day_of_week) - wday from_now += 7 unless from_now > 0 advance(days: from_now) end @@ -358,8 +356,7 @@ module DateAndTime # today.prev_occurring(:monday) # => Mon, 11 Dec 2017 # today.prev_occurring(:thursday) # => Thu, 07 Dec 2017 def prev_occurring(day_of_week) - current_day_number = wday != 0 ? wday - 1 : 6 - ago = current_day_number - DAYS_INTO_WEEK.fetch(day_of_week) + ago = wday - DAYS_INTO_WEEK.fetch(day_of_week) ago += 7 unless ago > 0 advance(days: -ago) end @@ -374,7 +371,7 @@ module DateAndTime end def days_span(day) - (DAYS_INTO_WEEK[day] - DAYS_INTO_WEEK[Date.beginning_of_week]) % 7 + (DAYS_INTO_WEEK.fetch(day) - DAYS_INTO_WEEK.fetch(Date.beginning_of_week)) % 7 end def copy_time_to(other) diff --git a/activesupport/lib/active_support/core_ext/enumerable.rb b/activesupport/lib/active_support/core_ext/enumerable.rb index 7713c52cb1..d87d63f287 100644 --- a/activesupport/lib/active_support/core_ext/enumerable.rb +++ b/activesupport/lib/active_support/core_ext/enumerable.rb @@ -7,11 +7,15 @@ module Enumerable # Enumerable#sum was added in Ruby 2.4, but it only works with Numeric elements # when we omit an identity. + # :stopdoc: + # We can't use Refinements here because Refinements with Module which will be prepended # doesn't work well https://bugs.ruby-lang.org/issues/13446 - alias :_original_sum_with_required_identity :sum # :nodoc: + alias :_original_sum_with_required_identity :sum private :_original_sum_with_required_identity + # :startdoc: + # Calculates a sum from the elements. # # payments.sum { |p| p.price * p.tax_rate } diff --git a/activesupport/lib/active_support/core_ext/object/to_query.rb b/activesupport/lib/active_support/core_ext/object/to_query.rb index abb461966a..bac6ff9c97 100644 --- a/activesupport/lib/active_support/core_ext/object/to_query.rb +++ b/activesupport/lib/active_support/core_ext/object/to_query.rb @@ -75,11 +75,14 @@ class Hash # # This method is also aliased as +to_param+. def to_query(namespace = nil) - collect do |key, value| + query = collect do |key, value| unless (value.is_a?(Hash) || value.is_a?(Array)) && value.empty? value.to_query(namespace ? "#{namespace}[#{key}]" : key) end - end.compact.sort! * "&" + end.compact + + query.sort! unless namespace.to_s.include?("[]") + query.join("&") end alias_method :to_param, :to_query diff --git a/activesupport/lib/active_support/core_ext/range/compare_range.rb b/activesupport/lib/active_support/core_ext/range/compare_range.rb index 704041f6de..6f6d2a27bb 100644 --- a/activesupport/lib/active_support/core_ext/range/compare_range.rb +++ b/activesupport/lib/active_support/core_ext/range/compare_range.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module ActiveSupport - module CompareWithRange #:nodoc: + module CompareWithRange # Extends the default Range#=== to support range comparisons. # (1..5) === (1..5) # => true # (1..5) === (2..3) # => true 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/lazy_load_hooks.rb b/activesupport/lib/active_support/lazy_load_hooks.rb index dc8080c469..a6b096a973 100644 --- a/activesupport/lib/active_support/lazy_load_hooks.rb +++ b/activesupport/lib/active_support/lazy_load_hooks.rb @@ -68,7 +68,11 @@ module ActiveSupport if options[:yield] block.call(base) else - base.instance_eval(&block) + if base.is_a?(Module) + base.class_eval(&block) + else + base.instance_eval(&block) + end end end end diff --git a/activesupport/lib/active_support/testing/assertions.rb b/activesupport/lib/active_support/testing/assertions.rb index 6a56da384f..b27ac7ce99 100644 --- a/activesupport/lib/active_support/testing/assertions.rb +++ b/activesupport/lib/active_support/testing/assertions.rb @@ -113,11 +113,23 @@ module ActiveSupport # post :create, params: { article: invalid_attributes } # end # + # A lambda can be passed in and evaluated. + # + # assert_no_difference -> { Article.count } do + # post :create, params: { article: invalid_attributes } + # end + # # An error message can be specified. # # assert_no_difference 'Article.count', 'An Article should not be created' do # post :create, params: { article: invalid_attributes } # end + # + # An array of expressions can also be passed in and evaluated. + # + # assert_no_difference [ 'Article.count', -> { Post.count } ] do + # post :create, params: { article: invalid_attributes } + # end def assert_no_difference(expression, message = nil, &block) assert_difference expression, 0, message, &block end 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/cache/stores/redis_cache_store_test.rb b/activesupport/test/cache/stores/redis_cache_store_test.rb index 24c4c5c481..3b873de383 100644 --- a/activesupport/test/cache/stores/redis_cache_store_test.rb +++ b/activesupport/test/cache/stores/redis_cache_store_test.rb @@ -141,6 +141,46 @@ module ActiveSupport::Cache::RedisCacheStoreTests end end end + + def test_increment_expires_in + assert_called_with @cache.redis, :incrby, [ "#{@namespace}:foo", 1 ] do + assert_called_with @cache.redis, :expire, [ "#{@namespace}:foo", 60 ] do + @cache.increment "foo", 1, expires_in: 60 + end + end + + # key and ttl exist + @cache.redis.setex "#{@namespace}:bar", 120, 1 + assert_not_called @cache.redis, :expire do + @cache.increment "bar", 1, expires_in: 2.minutes + end + + # key exist but not have expire + @cache.redis.set "#{@namespace}:dar", 10 + assert_called_with @cache.redis, :expire, [ "#{@namespace}:dar", 60 ] do + @cache.increment "dar", 1, expires_in: 60 + end + end + + def test_decrement_expires_in + assert_called_with @cache.redis, :decrby, [ "#{@namespace}:foo", 1 ] do + assert_called_with @cache.redis, :expire, [ "#{@namespace}:foo", 60 ] do + @cache.decrement "foo", 1, expires_in: 60 + end + end + + # key and ttl exist + @cache.redis.setex "#{@namespace}:bar", 120, 1 + assert_not_called @cache.redis, :expire do + @cache.decrement "bar", 1, expires_in: 2.minutes + end + + # key exist but not have expire + @cache.redis.set "#{@namespace}:dar", 10 + assert_called_with @cache.redis, :expire, [ "#{@namespace}:dar", 60 ] do + @cache.decrement "dar", 1, expires_in: 60 + end + end end class ConnectionPoolBehaviourTest < StoreTest diff --git a/activesupport/test/core_ext/duration_test.rb b/activesupport/test/core_ext/duration_test.rb index 240ae3bde0..63934e2433 100644 --- a/activesupport/test/core_ext/duration_test.rb +++ b/activesupport/test/core_ext/duration_test.rb @@ -158,6 +158,18 @@ class DurationTest < ActiveSupport::TestCase assert_equal Date.civil(2017, 1, 3), Date.civil(2017, 1, 1) + 1.day * 2 end + def test_date_added_with_multiplied_duration_larger_than_one_month + assert_equal Date.civil(2017, 2, 15), Date.civil(2017, 1, 1) + 1.day * 45 + end + + def test_date_added_with_divided_duration + assert_equal Date.civil(2017, 1, 3), Date.civil(2017, 1, 1) + 4.days / 2 + end + + def test_date_added_with_divided_duration_larger_than_one_month + assert_equal Date.civil(2017, 2, 15), Date.civil(2017, 1, 1) + 90.days / 2 + end + def test_plus_with_time assert_equal 1 + 1.second, 1.second + 1, "Duration + Numeric should == Numeric + Duration" end diff --git a/activesupport/test/core_ext/object/to_query_test.rb b/activesupport/test/core_ext/object/to_query_test.rb index 7593bcfa4d..b0b7ef0913 100644 --- a/activesupport/test/core_ext/object/to_query_test.rb +++ b/activesupport/test/core_ext/object/to_query_test.rb @@ -77,6 +77,20 @@ class ToQueryTest < ActiveSupport::TestCase assert_equal "name=Nakshay&type=human", hash.to_query end + def test_hash_not_sorted_lexicographically_for_nested_structure + params = { + "foo" => { + "contents" => [ + { "name" => "gorby", "id" => "123" }, + { "name" => "puff", "d" => "true" } + ] + } + } + expected = "foo[contents][][name]=gorby&foo[contents][][id]=123&foo[contents][][name]=puff&foo[contents][][d]=true" + + assert_equal expected, URI.decode(params.to_query) + end + private def assert_query_equal(expected, actual) assert_equal expected.split("&"), actual.to_query.split("&") diff --git a/activesupport/test/lazy_load_hooks_test.rb b/activesupport/test/lazy_load_hooks_test.rb index 721d44d0c1..50a703e49f 100644 --- a/activesupport/test/lazy_load_hooks_test.rb +++ b/activesupport/test/lazy_load_hooks_test.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require "abstract_unit" +require "active_support/core_ext/module/remove_method" class LazyLoadHooksTest < ActiveSupport::TestCase def test_basic_hook @@ -125,6 +126,54 @@ class LazyLoadHooksTest < ActiveSupport::TestCase assert_equal 7, i end + def test_hook_uses_class_eval_when_base_is_a_class + ActiveSupport.on_load(:uses_class_eval) do + def first_wrestler + "John Cena" + end + end + + ActiveSupport.run_load_hooks(:uses_class_eval, FakeContext) + assert_equal "John Cena", FakeContext.new(0).first_wrestler + ensure + FakeContext.remove_possible_method(:first_wrestler) + end + + def test_hook_uses_class_eval_when_base_is_a_module + mod = Module.new + ActiveSupport.on_load(:uses_class_eval2) do + def last_wrestler + "Dwayne Johnson" + end + end + ActiveSupport.run_load_hooks(:uses_class_eval2, mod) + + klass = Class.new do + include mod + end + + assert_equal "Dwayne Johnson", klass.new.last_wrestler + end + + def test_hook_uses_instance_eval_when_base_is_an_instance + ActiveSupport.on_load(:uses_instance_eval) do + def second_wrestler + "Hulk Hogan" + end + end + + context = FakeContext.new(1) + ActiveSupport.run_load_hooks(:uses_instance_eval, context) + + assert_raises NoMethodError do + FakeContext.new(2).second_wrestler + end + assert_raises NoMethodError do + FakeContext.second_wrestler + end + assert_equal "Hulk Hogan", context.second_wrestler + end + private def incr_amt diff --git a/activesupport/test/logger_test.rb b/activesupport/test/logger_test.rb index 5efbd10a7d..773b0daa1d 100644 --- a/activesupport/test/logger_test.rb +++ b/activesupport/test/logger_test.rb @@ -5,6 +5,7 @@ require "multibyte_test_helpers" require "stringio" require "fileutils" require "tempfile" +require "tmpdir" require "concurrent/atomics" class LoggerTest < ActiveSupport::TestCase diff --git a/activesupport/test/multibyte_conformance_test.rb b/activesupport/test/multibyte_conformance_test.rb index 748e8d16e1..a704505fc6 100644 --- a/activesupport/test/multibyte_conformance_test.rb +++ b/activesupport/test/multibyte_conformance_test.rb @@ -3,15 +3,10 @@ require "abstract_unit" require "multibyte_test_helpers" -require "fileutils" -require "open-uri" -require "tmpdir" - class MultibyteConformanceTest < ActiveSupport::TestCase include MultibyteTestHelpers UNIDATA_FILE = "/NormalizationTest.txt" - FileUtils.mkdir_p(CACHE_DIR) RUN_P = begin Downloader.download(UNIDATA_URL + UNIDATA_FILE, CACHE_DIR + UNIDATA_FILE) rescue diff --git a/activesupport/test/multibyte_grapheme_break_conformance_test.rb b/activesupport/test/multibyte_grapheme_break_conformance_test.rb index fac74cd80f..61b171a8d4 100644 --- a/activesupport/test/multibyte_grapheme_break_conformance_test.rb +++ b/activesupport/test/multibyte_grapheme_break_conformance_test.rb @@ -3,10 +3,6 @@ require "abstract_unit" require "multibyte_test_helpers" -require "fileutils" -require "open-uri" -require "tmpdir" - class MultibyteGraphemeBreakConformanceTest < ActiveSupport::TestCase include MultibyteTestHelpers diff --git a/activesupport/test/multibyte_normalization_conformance_test.rb b/activesupport/test/multibyte_normalization_conformance_test.rb index 1173a94e81..3674ea44f3 100644 --- a/activesupport/test/multibyte_normalization_conformance_test.rb +++ b/activesupport/test/multibyte_normalization_conformance_test.rb @@ -3,10 +3,6 @@ require "abstract_unit" require "multibyte_test_helpers" -require "fileutils" -require "open-uri" -require "tmpdir" - class MultibyteNormalizationConformanceTest < ActiveSupport::TestCase include MultibyteTestHelpers diff --git a/activesupport/test/multibyte_test_helpers.rb b/activesupport/test/multibyte_test_helpers.rb index f7cf993100..98f36aa939 100644 --- a/activesupport/test/multibyte_test_helpers.rb +++ b/activesupport/test/multibyte_test_helpers.rb @@ -1,5 +1,9 @@ # frozen_string_literal: true +require "fileutils" +require "open-uri" +require "tmpdir" + module MultibyteTestHelpers class Downloader def self.download(from, to) diff --git a/activesupport/test/test_case_test.rb b/activesupport/test/test_case_test.rb index 19901fad99..8698c66e6d 100644 --- a/activesupport/test/test_case_test.rb +++ b/activesupport/test/test_case_test.rb @@ -52,6 +52,22 @@ class AssertionsTest < ActiveSupport::TestCase assert_equal "Object Changed.\n\"@object.num\" didn't change by 0.\nExpected: 0\n Actual: 1", error.message end + def test_assert_no_difference_with_multiple_expressions_pass + another_object = @object.dup + assert_no_difference ["@object.num", -> { another_object.num }] do + # ... + end + end + + def test_assert_no_difference_with_multiple_expressions_fail + another_object = @object.dup + assert_raises(Minitest::Assertion) do + assert_no_difference ["@object.num", -> { another_object.num }], "Another Object Changed" do + another_object.increment + end + end + end + def test_assert_difference assert_difference "@object.num", +1 do @object.increment diff --git a/activesupport/test/testing/method_call_assertions_test.rb b/activesupport/test/testing/method_call_assertions_test.rb index 4af000bb7e..0500e47def 100644 --- a/activesupport/test/testing/method_call_assertions_test.rb +++ b/activesupport/test/testing/method_call_assertions_test.rb @@ -1,11 +1,8 @@ # frozen_string_literal: true require "abstract_unit" -require "active_support/testing/method_call_assertions" class MethodCallAssertionsTest < ActiveSupport::TestCase - include ActiveSupport::Testing::MethodCallAssertions - class Level def increment; 1; end def decrement; end 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") diff --git a/guides/source/action_controller_overview.md b/guides/source/action_controller_overview.md index 60a19542e6..b912265754 100644 --- a/guides/source/action_controller_overview.md +++ b/guides/source/action_controller_overview.md @@ -334,26 +334,24 @@ with a `has_many` association: params.require(:book).permit(:title, chapters_attributes: [:title]) ``` -#### Outside the Scope of Strong Parameters - -The strong parameter API was designed with the most common use cases -in mind. It is not meant as a silver bullet to handle all of your -whitelisting problems. However, you can easily mix the API with your -own code to adapt to your situation. - Imagine a scenario where you have parameters representing a product name and a hash of arbitrary data associated with that product, and you want to whitelist the product name attribute and also the whole -data hash. The strong parameters API doesn't let you directly -whitelist the whole of a nested hash with any keys, but you can use -the keys of your nested hash to declare what to whitelist: +data hash: ```ruby def product_params - params.require(:product).permit(:name, data: params[:product][:data].try(:keys)) + params.require(:product).permit(:name, data: {}) end ``` +#### Outside the Scope of Strong Parameters + +The strong parameter API was designed with the most common use cases +in mind. It is not meant as a silver bullet to handle all of your +whitelisting problems. However, you can easily mix the API with your +own code to adapt to your situation. + Session ------- diff --git a/guides/source/action_mailer_basics.md b/guides/source/action_mailer_basics.md index 86d06508b0..1f8c96ae43 100644 --- a/guides/source/action_mailer_basics.md +++ b/guides/source/action_mailer_basics.md @@ -217,6 +217,8 @@ pending jobs on restart. If you need a persistent backend, you will need to use an Active Job adapter that has a persistent backend (Sidekiq, Resque, etc). +NOTE: When calling `deliver_later` the job will be placed under `mailers` queue. Make sure Active Job adapter support it otherwise the job may be silently ignored preventing email delivery. You can change that by specifying `config.action_mailer.deliver_later_queue_name` option. + If you want to send emails right away (from a cronjob for example) just call `deliver_now`: diff --git a/guides/source/active_model_basics.md b/guides/source/active_model_basics.md index 4b0ea32d7c..09b4782eca 100644 --- a/guides/source/active_model_basics.md +++ b/guides/source/active_model_basics.md @@ -459,17 +459,18 @@ features out of the box. `ActiveModel::SecurePassword` provides a way to securely store any password in an encrypted form. When you include this module, a `has_secure_password` class method is provided which defines -a `password` accessor with certain validations on it. +a `password` accessor with certain validations on it by default. #### Requirements `ActiveModel::SecurePassword` depends on [`bcrypt`](https://github.com/codahale/bcrypt-ruby 'BCrypt'), so include this gem in your `Gemfile` to use `ActiveModel::SecurePassword` correctly. -In order to make this work, the model must have an accessor named `password_digest`. -The `has_secure_password` will add the following validations on the `password` accessor: +In order to make this work, the model must have an accessor named `XXX_digest`. +Where `XXX` is the attribute name of your desired password. +The following validations are added automatically: 1. Password should be present. -2. Password should be equal to its confirmation (provided `password_confirmation` is passed along). +2. Password should be equal to its confirmation (provided `XXX_confirmation` is passed along). 3. The maximum length of a password is 72 (required by `bcrypt` on which ActiveModel::SecurePassword depends) #### Examples @@ -478,7 +479,9 @@ The `has_secure_password` will add the following validations on the `password` a class Person include ActiveModel::SecurePassword has_secure_password - attr_accessor :password_digest + has_secure_password :recovery_password, validations: false + + attr_accessor :password_digest, :recovery_password_digest end person = Person.new @@ -502,4 +505,17 @@ person.valid? # => true # When all validations are passed. person.password = person.password_confirmation = 'aditya' person.valid? # => true + +person.recovery_password = "42password" + +person.authenticate('aditya') # => person +person.authenticate('notright') # => false +person.authenticate_password('aditya') # => person +person.authenticate_password('notright') # => false + +person.authenticate_recovery_password('42password') # => person +person.authenticate_recovery_password('notright') # => false + +person.password_digest # => "$2a$04$gF8RfZdoXHvyTjHhiU4ZsO.kQqV9oonYZu31PRE4hLQn3xM2qkpIy" +person.recovery_password_digest # => "$2a$04$iOfhwahFymCs5weB3BNH/uXkTG65HR.qpW.bNhEjFP3ftli3o5DQC" ``` diff --git a/guides/source/active_record_callbacks.md b/guides/source/active_record_callbacks.md index 0f74daace6..379c0925b5 100644 --- a/guides/source/active_record_callbacks.md +++ b/guides/source/active_record_callbacks.md @@ -184,9 +184,9 @@ class Company < ApplicationRecord after_touch :log_when_employees_or_company_touched private - def log_when_employees_or_company_touched - puts 'Employee/Company was touched' - end + def log_when_employees_or_company_touched + puts 'Employee/Company was touched' + end end >> @employee = Employee.last @@ -194,8 +194,8 @@ end # triggers @employee.company.touch >> @employee.touch -Employee/Company was touched An Employee was touched +Employee/Company was touched => true ``` diff --git a/guides/source/active_record_migrations.md b/guides/source/active_record_migrations.md index dda87802bf..9d33de5fa2 100644 --- a/guides/source/active_record_migrations.md +++ b/guides/source/active_record_migrations.md @@ -560,7 +560,7 @@ argument. Provide the original column options too, otherwise Rails can't recreate the column exactly when rolling back: ```ruby -remove_column :posts, :slug, :string, null: false, default: '', index: true +remove_column :posts, :slug, :string, null: false, default: '' ``` If you're going to need to use any other methods, you should use `reversible` diff --git a/guides/source/active_record_querying.md b/guides/source/active_record_querying.md index 944cee8a23..6c57cd8b8e 100644 --- a/guides/source/active_record_querying.md +++ b/guides/source/active_record_querying.md @@ -1777,6 +1777,12 @@ Client.pluck(:name) # => ["David", "Jeremy", "Jose"] ``` +You are not limited to querying fields from a single table, you can query multiple tables as well. + +``` +Client.joins(:comments, :categories).pluck("clients.email, comments.title, categories.name") +``` + Furthermore, unlike `select` and other `Relation` scopes, `pluck` triggers an immediate query, and thus cannot be chained with any further scopes, although it can work with scopes already constructed earlier: diff --git a/guides/source/active_record_validations.md b/guides/source/active_record_validations.md index c7846a0283..3c51313906 100644 --- a/guides/source/active_record_validations.md +++ b/guides/source/active_record_validations.md @@ -1133,24 +1133,6 @@ person.errors.full_messages # => ["Name cannot contain the characters !@#%*()_-+="] ``` -An equivalent to `errors#add` is to use `<<` to append a message to the `errors.messages` array for an attribute: - -```ruby - class Person < ApplicationRecord - def a_method_used_for_validation_purposes - errors.messages[:name] << "cannot contain the characters !@#%*()_-+=" - end - end - - person = Person.create(name: "!@#") - - person.errors[:name] - # => ["cannot contain the characters !@#%*()_-+="] - - person.errors.to_a - # => ["Name cannot contain the characters !@#%*()_-+="] -``` - ### `errors.details` You can specify a validator type to the returned error details hash using the diff --git a/guides/source/active_storage_overview.md b/guides/source/active_storage_overview.md index 91ad089d40..e6c8b503a8 100644 --- a/guides/source/active_storage_overview.md +++ b/guides/source/active_storage_overview.md @@ -160,7 +160,7 @@ google: type: "service_account" project_id: "" private_key_id: <%= Rails.application.credentials.dig(:gcs, :private_key_id) %> - private_key: <%= Rails.application.credentials.dig(:gcs, :private_key) %> + private_key: <%= Rails.application.credentials.dig(:gcs, :private_key).dump %> client_email: "" client_id: "" auth_uri: "https://accounts.google.com/o/oauth2/auth" @@ -211,6 +211,8 @@ production: NOTE: Files are served from the primary service. +NOTE: This is not compatible with the [direct uploads](#direct-uploads) feature. + Attaching Files to Records -------------------------- @@ -230,6 +232,10 @@ end You can create a user with an avatar: +```erb +<%= form.file_field :avatar %> +``` + ```ruby class SignupController < ApplicationController def create @@ -248,13 +254,13 @@ end Call `avatar.attach` to attach an avatar to an existing user: ```ruby -Current.user.avatar.attach(params[:avatar]) +user.avatar.attach(params[:avatar]) ``` Call `avatar.attached?` to determine whether a particular user has an avatar: ```ruby -Current.user.avatar.attached? +user.avatar.attached? ``` ### `has_many_attached` @@ -326,7 +332,7 @@ You can bypass the content type inference from the data by passing in @message.image.attach( io: File.open('/path/to/file'), filename: 'file.pdf', - content_type: 'application/pdf' + content_type: 'application/pdf', identify: false ) ``` @@ -446,11 +452,12 @@ the box, Active Storage supports previewing videos and PDF documents. </ul> ``` -WARNING: Extracting previews requires third-party applications, `ffmpeg` for -video and `mutool` for PDFs. These libraries are not provided by Rails. You must -install them yourself to use the built-in previewers. Before you install and use -third-party software, make sure you understand the licensing implications of -doing so. +WARNING: Extracting previews requires third-party applications, FFmpeg for +video and muPDF for PDFs, and on macOS also XQuartz and Poppler. +These libraries are not provided by Rails. You must install them yourself to +use the built-in previewers. Before you install and use third-party software, +make sure you understand the licensing implications of doing so. + Direct Uploads -------------- @@ -478,7 +485,7 @@ directly from the client to the cloud. 2. Annotate file inputs with the direct upload URL. - ```ruby + ```erb <%= form.file_field :attachments, multiple: true, direct_upload: true %> ``` 3. That's it! Uploads begin upon form submission. diff --git a/guides/source/active_support_core_extensions.md b/guides/source/active_support_core_extensions.md index 057651e0cf..470ddadeb5 100644 --- a/guides/source/active_support_core_extensions.md +++ b/guides/source/active_support_core_extensions.md @@ -2045,10 +2045,10 @@ The method `index_with` generates a hash with the elements of an enumerable as k is either a passed default or returned in a block. ```ruby -%i( title body created_at ).index_with { |attr_name| public_send(attr_name) } +%i( title body created_at ).index_with { |attr_name| post.public_send(attr_name) } # => { title: "hey", body: "what's up?", … } -WEEKDAYS.index_with([ Interval.all_day ]) +WEEKDAYS.index_with(Interval.all_day) # => { monday: [ 0, 1440 ], … } ``` @@ -2935,34 +2935,6 @@ Extensions to `Date` ### Calculations -NOTE: All the following methods are defined in `active_support/core_ext/date/calculations.rb`. - -```ruby -yesterday -tomorrow -beginning_of_week (at_beginning_of_week) -end_of_week (at_end_of_week) -monday -sunday -weeks_ago -prev_week (last_week) -next_week -months_ago -months_since -beginning_of_month (at_beginning_of_month) -end_of_month (at_end_of_month) -last_month -beginning_of_quarter (at_beginning_of_quarter) -end_of_quarter (at_end_of_quarter) -beginning_of_year (at_beginning_of_year) -end_of_year (at_end_of_year) -years_ago -years_since -last_year -on_weekday? -on_weekend? -``` - INFO: The following calculation methods have edge cases in October 1582, since days 5..14 just do not exist. This guide does not document their behavior around those days for brevity, but it is enough to say that they do what you would expect. That is, `Date.new(1582, 10, 4).tomorrow` returns `Date.new(1582, 10, 15)` and so on. Please check `test/core_ext/date_ext_test.rb` in the Active Support test suite for expected behavior. #### `Date.current` @@ -2971,6 +2943,8 @@ Active Support defines `Date.current` to be today in the current time zone. That When making Date comparisons using methods which honor the user time zone, make sure to use `Date.current` and not `Date.today`. There are cases where the user time zone might be in the future compared to the system time zone, which `Date.today` uses by default. This means `Date.today` may equal `Date.yesterday`. +NOTE: Defined in `active_support/core_ext/date/calculations.rb`. + #### Named dates ##### `beginning_of_week`, `end_of_week` @@ -2990,6 +2964,8 @@ d.end_of_week(:sunday) # => Sat, 08 May 2010 `beginning_of_week` is aliased to `at_beginning_of_week` and `end_of_week` is aliased to `at_end_of_week`. +NOTE: Defined in `active_support/core_ext/date_and_time/calculations.rb`. + ##### `monday`, `sunday` The methods `monday` and `sunday` return the dates for the previous Monday and @@ -3007,6 +2983,8 @@ d = Date.new(2012, 9, 16) # => Sun, 16 Sep 2012 d.sunday # => Sun, 16 Sep 2012 ``` +NOTE: Defined in `active_support/core_ext/date_and_time/calculations.rb`. + ##### `prev_week`, `next_week` The method `next_week` receives a symbol with a day name in English (default is the thread local `Date.beginning_of_week`, or `config.beginning_of_week`, or `:monday`) and it returns the date corresponding to that day. @@ -3029,6 +3007,8 @@ d.prev_week(:friday) # => Fri, 30 Apr 2010 Both `next_week` and `prev_week` work as expected when `Date.beginning_of_week` or `config.beginning_of_week` are set. +NOTE: Defined in `active_support/core_ext/date_and_time/calculations.rb`. + ##### `beginning_of_month`, `end_of_month` The methods `beginning_of_month` and `end_of_month` return the dates for the beginning and end of the month: @@ -3041,6 +3021,8 @@ d.end_of_month # => Mon, 31 May 2010 `beginning_of_month` is aliased to `at_beginning_of_month`, and `end_of_month` is aliased to `at_end_of_month`. +NOTE: Defined in `active_support/core_ext/date_and_time/calculations.rb`. + ##### `beginning_of_quarter`, `end_of_quarter` The methods `beginning_of_quarter` and `end_of_quarter` return the dates for the beginning and end of the quarter of the receiver's calendar year: @@ -3053,6 +3035,8 @@ d.end_of_quarter # => Wed, 30 Jun 2010 `beginning_of_quarter` is aliased to `at_beginning_of_quarter`, and `end_of_quarter` is aliased to `at_end_of_quarter`. +NOTE: Defined in `active_support/core_ext/date_and_time/calculations.rb`. + ##### `beginning_of_year`, `end_of_year` The methods `beginning_of_year` and `end_of_year` return the dates for the beginning and end of the year: @@ -3065,6 +3049,8 @@ d.end_of_year # => Fri, 31 Dec 2010 `beginning_of_year` is aliased to `at_beginning_of_year`, and `end_of_year` is aliased to `at_end_of_year`. +NOTE: Defined in `active_support/core_ext/date_and_time/calculations.rb`. + #### Other Date Computations ##### `years_ago`, `years_since` @@ -3092,6 +3078,8 @@ Date.new(2012, 2, 29).years_since(3) # => Sat, 28 Feb 2015 `last_year` is short-hand for `#years_ago(1)`. +NOTE: Defined in `active_support/core_ext/date_and_time/calculations.rb`. + ##### `months_ago`, `months_since` The methods `months_ago` and `months_since` work analogously for months: @@ -3110,6 +3098,8 @@ Date.new(2009, 12, 31).months_since(2) # => Sun, 28 Feb 2010 `last_month` is short-hand for `#months_ago(1)`. +NOTE: Defined in `active_support/core_ext/date_and_time/calculations.rb`. + ##### `weeks_ago` The method `weeks_ago` works analogously for weeks: @@ -3119,6 +3109,8 @@ Date.new(2010, 5, 24).weeks_ago(1) # => Mon, 17 May 2010 Date.new(2010, 5, 24).weeks_ago(2) # => Mon, 10 May 2010 ``` +NOTE: Defined in `active_support/core_ext/date_and_time/calculations.rb`. + ##### `advance` The most generic way to jump to other days is `advance`. This method receives a hash with keys `:years`, `:months`, `:weeks`, `:days`, and returns a date advanced as much as the present keys indicate: @@ -3147,6 +3139,8 @@ Date.new(2010, 2, 28).advance(days: 1).advance(months: 1) # => Thu, 01 Apr 2010 ``` +NOTE: Defined in `active_support/core_ext/date/calculations.rb`. + #### Changing Components The method `change` allows you to get a new date which is the same as the receiver except for the given year, month, or day: @@ -3163,6 +3157,8 @@ Date.new(2010, 1, 31).change(month: 2) # => ArgumentError: invalid date ``` +NOTE: Defined in `active_support/core_ext/date/calculations.rb`. + #### Durations Durations can be added to and subtracted from dates: @@ -3205,6 +3201,8 @@ date.end_of_day # => Mon Jun 07 23:59:59 +0200 2010 `beginning_of_day` is aliased to `at_beginning_of_day`, `midnight`, `at_midnight`. +NOTE: Defined in `active_support/core_ext/date/calculations.rb`. + ##### `beginning_of_hour`, `end_of_hour` The method `beginning_of_hour` returns a timestamp at the beginning of the hour (hh:00:00): @@ -3223,6 +3221,8 @@ date.end_of_hour # => Mon Jun 07 19:59:59 +0200 2010 `beginning_of_hour` is aliased to `at_beginning_of_hour`. +NOTE: Defined in `active_support/core_ext/date_time/calculations.rb`. + ##### `beginning_of_minute`, `end_of_minute` The method `beginning_of_minute` returns a timestamp at the beginning of the minute (hh:mm:00): @@ -3243,6 +3243,8 @@ date.end_of_minute # => Mon Jun 07 19:55:59 +0200 2010 INFO: `beginning_of_hour`, `end_of_hour`, `beginning_of_minute` and `end_of_minute` are implemented for `Time` and `DateTime` but **not** `Date` as it does not make sense to request the beginning or end of an hour or minute on a `Date` instance. +NOTE: Defined in `active_support/core_ext/date_time/calculations.rb`. + ##### `ago`, `since` The method `ago` receives a number of seconds as argument and returns a timestamp those many seconds ago from midnight: @@ -3259,6 +3261,8 @@ date = Date.current # => Fri, 11 Jun 2010 date.since(1) # => Fri, 11 Jun 2010 00:00:01 EDT -04:00 ``` +NOTE: Defined in `active_support/core_ext/date/calculations.rb`. + #### Other Time Computations ### Conversions @@ -3270,8 +3274,6 @@ WARNING: `DateTime` is not aware of DST rules and so some of these methods have ### Calculations -NOTE: All the following methods are defined in `active_support/core_ext/date_time/calculations.rb`. - The class `DateTime` is a subclass of `Date` so by loading `active_support/core_ext/date/calculations.rb` you inherit these methods and their aliases, except that they will always return datetimes. The following methods are reimplemented so you do **not** need to load `active_support/core_ext/date/calculations.rb` for these ones: @@ -3298,6 +3300,8 @@ end_of_hour Active Support defines `DateTime.current` to be like `Time.now.to_datetime`, except that it honors the user time zone, if defined. It also defines `DateTime.yesterday` and `DateTime.tomorrow`, and the instance predicates `past?`, and `future?` relative to `DateTime.current`. +NOTE: Defined in `active_support/core_ext/date_time/calculations.rb`. + #### Other Extensions ##### `seconds_since_midnight` @@ -3309,6 +3313,8 @@ now = DateTime.current # => Mon, 07 Jun 2010 20:26:36 +0000 now.seconds_since_midnight # => 73596 ``` +NOTE: Defined in `active_support/core_ext/date_time/calculations.rb`. + ##### `utc` The method `utc` gives you the same datetime in the receiver expressed in UTC. @@ -3320,6 +3326,8 @@ now.utc # => Mon, 07 Jun 2010 23:27:52 +0000 This method is also aliased as `getutc`. +NOTE: Defined in `active_support/core_ext/date_time/calculations.rb`. + ##### `utc?` The predicate `utc?` says whether the receiver has UTC as its time zone: @@ -3330,6 +3338,8 @@ now.utc? # => false now.utc.utc? # => true ``` +NOTE: Defined in `active_support/core_ext/date_time/calculations.rb`. + ##### `advance` The most generic way to jump to another datetime is `advance`. This method receives a hash with keys `:years`, `:months`, `:weeks`, `:days`, `:hours`, `:minutes`, and `:seconds`, and returns a datetime advanced as much as the present keys indicate. @@ -3361,6 +3371,8 @@ d.advance(seconds: 1).advance(months: 1) WARNING: Since `DateTime` is not DST-aware you can end up in a non-existing point in time with no warning or error telling you so. +NOTE: Defined in `active_support/core_ext/date_time/calculations.rb`. + #### Changing Components The method `change` allows you to get a new datetime which is the same as the receiver except for the given options, which may include `:year`, `:month`, `:day`, `:hour`, `:min`, `:sec`, `:offset`, `:start`: @@ -3393,6 +3405,8 @@ DateTime.current.change(month: 2, day: 30) # => ArgumentError: invalid date ``` +NOTE: Defined in `active_support/core_ext/date_time/calculations.rb`. + #### Durations Durations can be added to and subtracted from datetimes: @@ -3418,52 +3432,6 @@ Extensions to `Time` ### Calculations -NOTE: All the following methods are defined in `active_support/core_ext/time/calculations.rb`. - -```ruby -past? -today? -future? -yesterday -tomorrow -seconds_since_midnight -change -advance -ago -since (in) -prev_day -next_day -beginning_of_day (midnight, at_midnight, at_beginning_of_day) -end_of_day -beginning_of_hour (at_beginning_of_hour) -end_of_hour -beginning_of_week (at_beginning_of_week) -end_of_week (at_end_of_week) -monday -sunday -weeks_ago -prev_week (last_week) -next_week -months_ago -months_since -beginning_of_month (at_beginning_of_month) -end_of_month (at_end_of_month) -prev_month -next_month -last_month -beginning_of_quarter (at_beginning_of_quarter) -end_of_quarter (at_end_of_quarter) -beginning_of_year (at_beginning_of_year) -end_of_year (at_end_of_year) -years_ago -years_since -prev_year -last_year -next_year -on_weekday? -on_weekend? -``` - They are analogous. Please refer to their documentation above and take into account the following differences: * `change` accepts an additional `:usec` option. @@ -3488,6 +3456,8 @@ Active Support defines `Time.current` to be today in the current time zone. That When making Time comparisons using methods which honor the user time zone, make sure to use `Time.current` instead of `Time.now`. There are cases where the user time zone might be in the future compared to the system time zone, which `Time.now` uses by default. This means `Time.now.to_date` may equal `Date.yesterday`. +NOTE: Defined in `active_support/core_ext/time/calculations.rb`. + #### `all_day`, `all_week`, `all_month`, `all_quarter` and `all_year` The method `all_day` returns a range representing the whole day of the current time. @@ -3516,6 +3486,8 @@ now.all_year # => Fri, 01 Jan 2010 00:00:00 UTC +00:00..Fri, 31 Dec 2010 23:59:59 UTC +00:00 ``` +NOTE: Defined in `active_support/core_ext/date_and_time/calculations.rb`. + #### `prev_day`, `next_day` In Ruby 1.9 `prev_day` and `next_day` return the date in the last or next day: @@ -3526,6 +3498,8 @@ d.prev_day # => Fri, 07 May 2010 d.next_day # => Sun, 09 May 2010 ``` +NOTE: Defined in `active_support/core_ext/date_and_time/calculations.rb`. + #### `prev_month`, `next_month` In Ruby 1.9 `prev_month` and `next_month` return the date with the same day in the last or next month: @@ -3545,6 +3519,8 @@ Date.new(2000, 5, 31).next_month # => Fri, 30 Jun 2000 Date.new(2000, 1, 31).next_month # => Tue, 29 Feb 2000 ``` +NOTE: Defined in `active_support/core_ext/date_and_time/calculations.rb`. + #### `prev_year`, `next_year` In Ruby 1.9 `prev_year` and `next_year` return a date with the same day/month in the last or next year: @@ -3563,6 +3539,8 @@ d.prev_year # => Sun, 28 Feb 1999 d.next_year # => Wed, 28 Feb 2001 ``` +NOTE: Defined in `active_support/core_ext/date_and_time/calculations.rb`. + #### `prev_quarter`, `next_quarter` `prev_quarter` and `next_quarter` return the date with the same day in the previous or next quarter: @@ -3584,6 +3562,8 @@ Time.local(2000, 11, 31).next_quarter # => 2001-03-01 00:00:00 +0200 `prev_quarter` is aliased to `last_quarter`. +NOTE: Defined in `active_support/core_ext/date_and_time/calculations.rb`. + ### Time Constructors Active Support defines `Time.current` to be `Time.zone.now` if there's a user time zone defined, with fallback to `Time.now`: diff --git a/guides/source/association_basics.md b/guides/source/association_basics.md index e7408b5a7f..67844ae7a4 100644 --- a/guides/source/association_basics.md +++ b/guides/source/association_basics.md @@ -96,7 +96,7 @@ end  -NOTE: `belongs_to` associations _must_ use the singular term. If you used the pluralized form in the above example for the `author` association in the `Book` model, you would be told that there was an "uninitialized constant Book::Authors". This is because Rails automatically infers the class name from the association name. If the association name is wrongly pluralized, then the inferred class will be wrongly pluralized too. +NOTE: `belongs_to` associations _must_ use the singular term. If you used the pluralized form in the above example for the `author` association in the `Book` model and tried to create the instance by `Book.create(authors: @author)`, you would be told that there was an "uninitialized constant Book::Authors". This is because Rails automatically infers the class name from the association name. If the association name is wrongly pluralized, then the inferred class will be wrongly pluralized too. The corresponding migration might look like this: diff --git a/guides/source/command_line.md b/guides/source/command_line.md index 58a2d6d30f..0c2b66da57 100644 --- a/guides/source/command_line.md +++ b/guides/source/command_line.md @@ -457,65 +457,90 @@ More information about migrations can be found in the [Migrations](active_record ### `notes` -`bin/rails notes` will search through your code for comments beginning with FIXME, OPTIMIZE, or TODO. The search is done in files with extension `.builder`, `.rb`, `.rake`, `.yml`, `.yaml`, `.ruby`, `.css`, `.js`, and `.erb` for both default and custom annotations. +`bin/rails notes` searches through your code for comments beginning with a specific keyword. You can refer to `bin/rails notes --help` for information about usage. + +By default, it will search in `app`, `config`, `db`, `lib`, and `test` directories for FIXME, OPTIMIZE, and TODO annotations in files with extension `.builder`, `.rb`, `.rake`, `.yml`, `.yaml`, `.ruby`, `.css`, `.js`, and `.erb`. ```bash $ bin/rails notes -(in /home/foobar/commandsapp) app/controllers/admin/users_controller.rb: * [ 20] [TODO] any other way to do this? * [132] [FIXME] high priority for next deploy -app/models/school.rb: +lib/school.rb: * [ 13] [OPTIMIZE] refactor this code to make it faster * [ 17] [FIXME] ``` -You can add support for new file extensions using `config.annotations.register_extensions` option, which receives a list of the extensions with its corresponding regex to match it up. - -```ruby -config.annotations.register_extensions("scss", "sass", "less") { |annotation| /\/\/\s*(#{annotation}):?\s*(.*)$/ } -``` +#### Annotations -If you are looking for a specific annotation, say FIXME, you can use `bin/rails notes:fixme`. Note that you have to lower case the annotation's name. +You can pass specific annotations by using the `--annotations` argument. By default, it will search for FIXME, OPTIMIZE, and TODO. +Note that annotations are case sensitive. ```bash -$ bin/rails notes:fixme -(in /home/foobar/commandsapp) +$ bin/rails notes --annotations FIXME RELEASE app/controllers/admin/users_controller.rb: - * [132] high priority for next deploy + * [101] [RELEASE] We need to look at this before next release + * [132] [FIXME] high priority for next deploy -app/models/school.rb: - * [ 17] +lib/school.rb: + * [ 17] [FIXME] ``` -You can also use custom annotations in your code and list them using `bin/rails notes:custom` by specifying the annotation using an environment variable `ANNOTATION`. +#### Directories + +You can add more default directories to search from by using `config.annotations.register_directories`. It receives a list of directory names. + +```ruby +config.annotations.register_directories("spec", "vendor") +``` ```bash -$ bin/rails notes:custom ANNOTATION=BUG -(in /home/foobar/commandsapp) -app/models/article.rb: - * [ 23] Have to fix this one before pushing! +$ bin/rails notes +app/controllers/admin/users_controller.rb: + * [ 20] [TODO] any other way to do this? + * [132] [FIXME] high priority for next deploy + +lib/school.rb: + * [ 13] [OPTIMIZE] Refactor this code to make it faster + * [ 17] [FIXME] + +spec/models/user_spec.rb: + * [122] [TODO] Verify the user that has a subscription works + +vendor/tools.rb: + * [ 56] [TODO] Get rid of this dependency ``` -NOTE. When using specific annotations and custom annotations, the annotation name (FIXME, BUG etc) is not displayed in the output lines. +#### Extensions -By default, `rails notes` will look in the `app`, `config`, `db`, `lib`, and `test` directories. If you would like to search other directories, you can configure them using `config.annotations.register_directories` option. +You can add more default file extensions to search from by using `config.annotations.register_extensions`. It receives a list of extensions with its corresponding regex to match it up. ```ruby -config.annotations.register_directories("spec", "vendor") +config.annotations.register_extensions("scss", "sass") { |annotation| /\/\/\s*(#{annotation}):?\s*(.*)$/ } ``` -You can also provide them as a comma separated list in the environment variable `SOURCE_ANNOTATION_DIRECTORIES`. - ```bash -$ export SOURCE_ANNOTATION_DIRECTORIES='spec,vendor' $ bin/rails notes -(in /home/foobar/commandsapp) -app/models/user.rb: - * [ 35] [FIXME] User should have a subscription at this point +app/controllers/admin/users_controller.rb: + * [ 20] [TODO] any other way to do this? + * [132] [FIXME] high priority for next deploy + +app/assets/stylesheets/application.css.sass: + * [ 34] [TODO] Use pseudo element for this class + +app/assets/stylesheets/application.css.scss: + * [ 1] [TODO] Split into multiple components + +lib/school.rb: + * [ 13] [OPTIMIZE] Refactor this code to make it faster + * [ 17] [FIXME] + spec/models/user_spec.rb: * [122] [TODO] Verify the user that has a subscription works + +vendor/tools.rb: + * [ 56] [TODO] Get rid of this dependency ``` ### `routes` @@ -633,9 +658,9 @@ $ cat config/database.yml # # Install the pg driver: # gem install pg -# On OS X with Homebrew: +# On macOS with Homebrew: # gem install pg -- --with-pg-config=/usr/local/bin/pg_config -# On OS X with MacPorts: +# On macOS with MacPorts: # gem install pg -- --with-pg-config=/opt/local/lib/postgresql84/bin/pg_config # On Windows: # gem install pg diff --git a/guides/source/configuring.md b/guides/source/configuring.md index d4aa6546a7..43c2ac6827 100644 --- a/guides/source/configuring.md +++ b/guides/source/configuring.md @@ -165,7 +165,7 @@ pipeline is enabled. It is set to `true` by default. * `config.assets.precompile` allows you to specify additional assets (other than `application.css` and `application.js`) which are to be precompiled when `rake assets:precompile` is run. -* `config.assets.unknown_asset_fallback` allows you to modify the behavior of the asset pipeline when an asset is not in the pipeline, if you use sprockets-rails 3.2.0 or newer. Defaults to `true`. +* `config.assets.unknown_asset_fallback` allows you to modify the behavior of the asset pipeline when an asset is not in the pipeline, if you use sprockets-rails 3.2.0 or newer. Defaults to `false`. * `config.assets.prefix` defines the prefix where assets are served from. Defaults to `/assets`. @@ -305,6 +305,10 @@ All these configuration options are delegated to the `I18n` library. config.i18n.fallbacks.map = { az: :tr, da: [:de, :en] } ``` +### Configuring Active Model + +* `config.active_model.i18n_full_message` is a boolean value which controls whether the `full_message` error format can be overridden at the attribute or model level in the locale files. This is `false` by default. + ### Configuring Active Record `config.active_record` includes a variety of configuration options: @@ -663,6 +667,12 @@ There are a number of settings available on `config.action_mailer`: config.action_mailer.interceptors = ["MailInterceptor"] ``` +* `config.action_mailer.preview_interceptors` registers interceptors which will be called before mail is previewed. + + ```ruby + config.action_mailer.preview_interceptors = ["MyPreviewMailInterceptor"] + ``` + * `config.action_mailer.preview_path` specifies the location of mailer previews. ```ruby @@ -697,6 +707,8 @@ There are a few configuration options available in Active Support: * `config.active_support.use_sha1_digests` specifies whether to use SHA-1 instead of MD5 to generate non-sensitive digests, such as the ETag header. Defaults to false. +* `config.active_support.use_authenticated_message_encryption` specifies whether to use AES-256-GCM authenticated encryption as the default cipher for encrypting messages instead of AES-256-CBC. This is false by default, but enabled when loading defaults for Rails 5.2. + * `ActiveSupport::Logger.silencer` is set to `false` to disable the ability to silence logging in a block. The default is `true`. * `ActiveSupport::Cache::Store.logger` specifies the logger to use within cache store operations. @@ -793,7 +805,7 @@ normal Rails server. config.active_storage.paths[:ffprobe] = '/usr/local/bin/ffprobe' ``` -* `config.active_storage.variable_content_types` accepts an array of strings indicating the content types that Active Storage can transform through ImageMagick. The default is `%w(image/png image/gif image/jpg image/jpeg image/vnd.adobe.photoshop)`. +* `config.active_storage.variable_content_types` accepts an array of strings indicating the content types that Active Storage can transform through ImageMagick. The default is `%w(image/png image/gif image/jpg image/jpeg image/vnd.adobe.photoshop image/vnd.microsoft.icon)`. * `config.active_storage.content_types_to_serve_as_binary` accepts an array of strings indicating the content types that Active Storage will always serve as an attachment, rather than inline. The default is `%w(text/html text/javascript image/svg+xml application/postscript application/x-shockwave-flash text/xml application/xml application/xhtml+xml)`. @@ -801,15 +813,22 @@ text/javascript image/svg+xml application/postscript application/x-shockwave-fla * `config.active_storage.queue` can be used to set the name of the Active Job queue used to perform jobs like analyzing the content of a blob or purging a blog. ```ruby - config.active_job.queue = :low_priority + config.active_storage.queue = :low_priority ``` * `config.active_storage.logger` can be used to set the logger used by Active Storage. Accepts a logger conforming to the interface of Log4r or the default Ruby Logger class. ```ruby - config.active_job.logger = ActiveSupport::Logger.new(STDOUT) + config.active_storage.logger = ActiveSupport::Logger.new(STDOUT) ``` +* `config.active_storage.service_urls_expire_in` determines the default expiry of URLs generated by: + * `ActiveStorage::Blob#service_url` + * `ActiveStorage::Blob#service_url_for_direct_upload` + * `ActiveStorage::Variant#service_url` + + The default is 5 minutes. + ### Configuring a Database Just about every Rails application will interact with a database. You can connect to the database by setting an environment variable `ENV['DATABASE_URL']` or by using a configuration file called `config/database.yml`. diff --git a/guides/source/contributing_to_ruby_on_rails.md b/guides/source/contributing_to_ruby_on_rails.md index ba5d7bbee8..6c0c7aefc1 100644 --- a/guides/source/contributing_to_ruby_on_rails.md +++ b/guides/source/contributing_to_ruby_on_rails.md @@ -374,12 +374,6 @@ You can invoke `test_jdbcmysql`, `test_jdbcsqlite3` or `test_jdbcpostgresql` als The test suite runs with warnings enabled. Ideally, Ruby on Rails should issue no warnings, but there may be a few, as well as some from third-party libraries. Please ignore (or fix!) them, if any, and submit patches that do not issue new warnings. -If you are sure about what you are doing and would like to have a more clear output, there's a way to override the flag: - -```bash -$ RUBYOPT=-W0 bundle exec rake test -``` - ### Updating the CHANGELOG The CHANGELOG is an important part of every release. It keeps the list of changes for every Rails version. diff --git a/guides/source/development_dependencies_install.md b/guides/source/development_dependencies_install.md index 50274d700b..d5dca88c64 100644 --- a/guides/source/development_dependencies_install.md +++ b/guides/source/development_dependencies_install.md @@ -376,3 +376,31 @@ command inside of the `activestorage` directory to install the dependencies: ```bash yarn install ``` + +Extracting previews, tested in ActiveStorage's test suite requires third-party +applications, FFmpeg for video and muPDF for PDFs, and on macOS also XQuartz +and Poppler. Without these applications installed, ActiveStorage tests will +raise errors. + +On macOS you can run: + +```bash +brew install ffmpeg +brew cask install xquartz +brew install mupdf-tools +brew install poppler +``` + +On Ubuntu, you can run: + +```bash +sudo apt-get update && install ffmpeg +sudo apt-get update && install mupdf mupdf-tools +``` + +On Fedora or CentOS, just run: + +```bash +sudo yum install ffmpeg +sudo yum install mupdf +``` diff --git a/guides/source/documents.yaml b/guides/source/documents.yaml index 5cddf79eeb..4dee34b1e7 100644 --- a/guides/source/documents.yaml +++ b/guides/source/documents.yaml @@ -65,17 +65,13 @@ url: routing.html description: This guide covers the user-facing features of Rails routing. If you want to understand how to use routing in your own Rails applications, start here. - - name: Digging Deeper + name: Other Components documents: - name: Active Support Core Extensions url: active_support_core_extensions.html description: This guide documents the Ruby core extensions defined in Active Support. - - name: Rails Internationalization (I18n) API - url: i18n.html - description: This guide covers how to add internationalization to your applications. Your application will be able to translate content to different languages, change pluralization rules, use correct date formats for each country, and so on. - - name: Action Mailer Basics url: action_mailer_basics.html description: This guide describes how to use Action Mailer to send and receive emails. @@ -88,6 +84,18 @@ url: active_storage_overview.html description: This guide covers how to attach files to your Active Record models. - + name: Action Cable Overview + url: action_cable_overview.html + description: This guide explains how Action Cable works, and how to use WebSockets to create real-time features. + +- + name: Digging Deeper + documents: + - + name: Rails Internationalization (I18n) API + url: i18n.html + description: This guide covers how to add internationalization to your applications. Your application will be able to translate content to different languages, change pluralization rules, use correct date formats for each country, and so on. + - name: Testing Rails Applications url: testing.html description: This is a rather comprehensive guide to the various testing facilities in Rails. It covers everything from 'What is a test?' to Integration Testing. Enjoy. @@ -137,10 +145,6 @@ name: Using Rails for API-only Applications url: api_app.html description: This guide explains how to effectively use Rails to develop a JSON API application. - - - name: Action Cable Overview - url: action_cable_overview.html - description: This guide explains how Action Cable works, and how to use WebSockets to create real-time features. - name: Extending Rails diff --git a/guides/source/engines.md b/guides/source/engines.md index 9dbce5d09b..470bb50ba7 100644 --- a/guides/source/engines.md +++ b/guides/source/engines.md @@ -313,6 +313,9 @@ The engine that this guide covers provides submitting articles and commenting functionality and follows a similar thread to the [Getting Started Guide](getting_started.html), with some new twists. +NOTE: For this section, make sure to run the commands in the root of the +`blorgh` engine's directory. + ### Generating an Article Resource The first thing to generate for a blog engine is the `Article` model and related @@ -695,7 +698,7 @@ pre-defined path which may be customizable. The engine contains migrations for the `blorgh_articles` and `blorgh_comments` table which need to be created in the application's database so that the engine's models can query them correctly. To copy these migrations into the -application run the following command from the `test/dummy` directory of your Rails engine: +application run the following command from the application's root: ```bash $ bin/rails blorgh:install:migrations diff --git a/guides/source/getting_started.md b/guides/source/getting_started.md index de2c459cff..61658cdfc9 100644 --- a/guides/source/getting_started.md +++ b/guides/source/getting_started.md @@ -1203,14 +1203,15 @@ it look as follows: This time we point the form to the `update` action, which is not defined yet but will be very soon. -Passing the article object to the method will automatically set the URL for +Passing the article object to the `form_with` method will automatically set the URL for submitting the edited article form. This option tells Rails that we want this form to be submitted via the `PATCH` HTTP method, which is the HTTP method you're expected to use to **update** resources according to the REST protocol. -The arguments to `form_with` could be model objects, say, `model: @article` which would -cause the helper to fill in the form with the fields of the object. Passing in a -symbol scope (`scope: :article`) just creates the fields but without anything filled into them. +Also, passing a model object to `form_with`, like `model: @article` in the edit +view above, will cause form helpers to fill in form fields with the corresponding +values of the object. Passing in a symbol scope such as `scope: :article`, as +was done in the new view, only creates empty form fields. More details can be found in [form_with documentation] (http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-form_with). diff --git a/guides/source/initialization.md b/guides/source/initialization.md index d3b122c7fe..65222aabda 100644 --- a/guides/source/initialization.md +++ b/guides/source/initialization.md @@ -45,7 +45,7 @@ load Gem.bin_path('railties', 'rails', version) ``` If you try out this command in a Rails console, you would see that this loads -`railties/exe/rails`. A part of the file `railties/exe/rails.rb` has the +`railties/exe/rails`. A part of the file `railties/exe/rails` has the following code: ```ruby diff --git a/guides/source/layouts_and_rendering.md b/guides/source/layouts_and_rendering.md index d7072a766b..ba3ef4679b 100644 --- a/guides/source/layouts_and_rendering.md +++ b/guides/source/layouts_and_rendering.md @@ -1210,7 +1210,7 @@ Partials are very useful in rendering collections. When you pass a collection to When a partial is called with a pluralized collection, then the individual instances of the partial have access to the member of the collection being rendered via a variable named after the partial. In this case, the partial is `_product`, and within the `_product` partial, you can refer to `product` to get the instance that is being rendered. -There is also a shorthand for this. Assuming `@products` is a collection of `product` instances, you can simply write this in the `index.html.erb` to produce the same result: +There is also a shorthand for this. Assuming `@products` is a collection of `Product` instances, you can simply write this in the `index.html.erb` to produce the same result: ```html+erb <h1>Products</h1> diff --git a/guides/source/testing.md b/guides/source/testing.md index 0a6d2d6555..7958236902 100644 --- a/guides/source/testing.md +++ b/guides/source/testing.md @@ -1476,7 +1476,7 @@ Testing Helpers --------------- A helper is just a simple module where you can define methods which are -available into your views. +available in your views. In order to test helpers, all you need to do is check that the output of the helper method matches what you'd expect. Tests related to the helpers are diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md index 83a57a8c6a..81cb5a6c9f 100644 --- a/railties/CHANGELOG.md +++ b/railties/CHANGELOG.md @@ -1,3 +1,22 @@ +* Deprecate `rails notes` subcommands in favor of passing an `annotations` argument to `rails notes`. + + The following subcommands are replaced by passing `--annotations` or `-a` to `rails notes`: + - `rails notes:custom ANNOTATION=custom` is deprecated in favor of using `rails notes -a custom`. + - `rails notes:optimize` is deprecated in favor of using `rails notes -a OPTIMIZE`. + - `rails notes:todo` is deprecated in favor of using`rails notes -a TODO`. + - `rails notes:fixme` is deprecated in favor of using `rails notes -a FIXME`. + + *Annie-Claude Côté* + +* Deprecate `SOURCE_ANNOTATION_DIRECTORIES` environment variable used by `rails notes` + through `Rails::SourceAnnotationExtractor::Annotation` in favor of using `config.annotations.register_directories`. + + *Annie-Claude Côté* + +* Deprecate `rake notes` in favor of `rails notes`. + + *Annie-Claude Côté* + * Don't generate unused files in `app:update` task Skip the assets' initializer when sprockets isn't loaded. diff --git a/railties/Rakefile b/railties/Rakefile index 8251b2bb32..e1be0ceb40 100644 --- a/railties/Rakefile +++ b/railties/Rakefile @@ -31,6 +31,8 @@ namespace :test do failing_files = [] dirs = (ENV["TEST_DIR"] || ENV["TEST_DIRS"] || "**").split(",") + test_options = ENV["TESTOPTS"].to_s.split(/[\s]+/) + test_files = dirs.map { |dir| "test/#{dir}/*_test.rb" } Dir[*test_files].each do |file| next true if file.start_with?("test/fixtures/") @@ -46,7 +48,7 @@ namespace :test do # We could run these in parallel, but pretty much all of the # railties tests already run in parallel, so ¯\_(⊙︿⊙)_/¯ Process.waitpid fork { - ARGV.clear + ARGV.clear.concat test_options Rake.application = nil load file diff --git a/railties/lib/rails/application/finisher.rb b/railties/lib/rails/application/finisher.rb index c4b188aeee..04aaf6dd9a 100644 --- a/railties/lib/rails/application/finisher.rb +++ b/railties/lib/rails/application/finisher.rb @@ -127,7 +127,7 @@ module Rails initializer :set_routes_reloader_hook do |app| reloader = routes_reloader reloader.eager_load = app.config.eager_load - reloader.execute_if_updated + reloader.execute reloaders << reloader app.reloader.to_run do # We configure #execute rather than #execute_if_updated because if diff --git a/railties/lib/rails/application/routes_reloader.rb b/railties/lib/rails/application/routes_reloader.rb index 2ef09b4162..3ecb8e264e 100644 --- a/railties/lib/rails/application/routes_reloader.rb +++ b/railties/lib/rails/application/routes_reloader.rb @@ -7,7 +7,7 @@ module Rails class RoutesReloader attr_reader :route_sets, :paths attr_accessor :eager_load - delegate :updated?, to: :updater + delegate :execute_if_updated, :execute, :updated?, to: :updater def initialize @paths = [] @@ -19,31 +19,15 @@ module Rails clear! load_paths finalize! + route_sets.each(&:eager_load!) if eager_load ensure revert end - def execute - ret = updater.execute - route_sets.each(&:eager_load!) if eager_load - ret - end - - def execute_if_updated - if updated = updater.execute_if_updated - route_sets.each(&:eager_load!) if eager_load - end - updated - end - private def updater - @updater ||= begin - updater = ActiveSupport::FileUpdateChecker.new(paths) { reload! } - updater.execute - updater - end + @updater ||= ActiveSupport::FileUpdateChecker.new(paths) { reload! } end def clear! diff --git a/railties/lib/rails/commands/notes/notes_command.rb b/railties/lib/rails/commands/notes/notes_command.rb new file mode 100644 index 0000000000..64b339b3cd --- /dev/null +++ b/railties/lib/rails/commands/notes/notes_command.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +require "rails/source_annotation_extractor" + +module Rails + module Command + class NotesCommand < Base # :nodoc: + class_option :annotations, aliases: "-a", desc: "Filter by specific annotations, e.g. Foobar TODO", type: :array, default: %w(OPTIMIZE FIXME TODO) + + def perform(*) + require_application_and_environment! + + deprecation_warning + display_annotations + end + + private + def display_annotations + annotations = options[:annotations] + tag = (annotations.length > 1) + + Rails::SourceAnnotationExtractor.enumerate annotations.join("|"), tag: tag, dirs: directories + end + + def directories + Rails::SourceAnnotationExtractor::Annotation.directories + source_annotation_directories + end + + def deprecation_warning + return if source_annotation_directories.empty? + ActiveSupport::Deprecation.warn("`SOURCE_ANNOTATION_DIRECTORIES` is deprecated and will be removed in Rails 6.1. You can add default directories by using config.annotations.register_directories instead.") + end + + def source_annotation_directories + ENV["SOURCE_ANNOTATION_DIRECTORIES"].to_s.split(",") + end + end + end +end diff --git a/railties/lib/rails/commands/server/server_command.rb b/railties/lib/rails/commands/server/server_command.rb index 77b6c1f65d..2c5440d9ec 100644 --- a/railties/lib/rails/commands/server/server_command.rb +++ b/railties/lib/rails/commands/server/server_command.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true require "fileutils" -require "optparse" require "action_dispatch" require "rails" require "active_support/deprecation" @@ -98,10 +97,6 @@ module Rails end end - def restart_command - "bin/rails server #{ARGV.join(' ')}" - end - def use_puma? server.to_s == "Rack::Handler::Puma" end @@ -133,16 +128,18 @@ module Rails desc: "Specifies the Rack server used to run the application (thin/puma/webrick).", banner: :name class_option :pid, aliases: "-P", type: :string, default: DEFAULT_PID_PATH, desc: "Specifies the PID file." - class_option "dev-caching", aliases: "-C", type: :boolean, default: nil, + class_option :dev_caching, aliases: "-C", type: :boolean, default: nil, desc: "Specifies whether to perform caching in development." - class_option "restart", type: :boolean, default: nil, hide: true - class_option "early_hints", type: :boolean, default: nil, desc: "Enables HTTP/2 early hints." + class_option :restart, type: :boolean, default: nil, hide: true + class_option :early_hints, type: :boolean, default: nil, desc: "Enables HTTP/2 early hints." + class_option :log_to_stdout, type: :boolean, default: nil, optional: true, + desc: "Whether to log to stdout. Enabled by default in development when not daemonized." - def initialize(args = [], local_options = {}, config = {}) - @original_options = local_options + def initialize(args, local_options, *) super - @using = deprecated_positional_rack_server(using) || options[:using] - @log_stdout = options[:daemon].blank? && (options[:environment] || Rails.env) == "development" + + @original_options = local_options - %w( --restart ) + deprecate_positional_rack_server_and_rewrite_to_option(@original_options) end def perform @@ -170,7 +167,7 @@ module Rails { user_supplied_options: user_supplied_options, server: using, - log_stdout: @log_stdout, + log_stdout: log_to_stdout?, Port: port, Host: host, DoNotReverseLookup: true, @@ -178,7 +175,7 @@ module Rails environment: environment, daemonize: options[:daemon], pid: pid, - caching: options["dev-caching"], + caching: options[:dev_caching], restart_cmd: restart_command, early_hints: early_hints } @@ -211,7 +208,7 @@ module Rails name = :Port when :binding name = :Host - when :"dev-caching" + when :dev_caching name = :caching when :daemonize name = :daemon @@ -253,13 +250,19 @@ module Rails end def restart_command - "bin/rails server #{using} #{@original_options.join(" ")} --restart" + "bin/rails server #{@original_options.join(" ")} --restart" end def early_hints options[:early_hints] end + def log_to_stdout? + options.fetch(:log_to_stdout) do + options[:daemon].blank? && environment == "development" + end + end + def pid File.expand_path(options[:pid]) end @@ -272,14 +275,19 @@ module Rails FileUtils.rm_f(options[:pid]) if options[:restart] end - def deprecated_positional_rack_server(value) - if value - ActiveSupport::Deprecation.warn(<<-MSG.squish) + def deprecate_positional_rack_server_and_rewrite_to_option(original_options) + if using + ActiveSupport::Deprecation.warn(<<~MSG) Passing the Rack server name as a regular argument is deprecated and will be removed in the next Rails version. Please, use the -u option instead. MSG - value + + original_options.concat [ "-u", using ] + else + # Use positional internally to get around Thor's immutable options. + # TODO: Replace `using` occurences with `options[:using]` after deprecation removal. + @using = options[:using] end end @@ -293,10 +301,10 @@ module Rails Run `rails server --help` for more options. MSG else - suggestions = Rails::Command::Spellchecker.suggest(server, from: RACK_SERVERS) + suggestion = Rails::Command::Spellchecker.suggest(server, from: RACK_SERVERS) <<~MSG - Could not find server "#{server}". Maybe you meant #{suggestions.inspect}? + Could not find server "#{server}". Maybe you meant #{suggestion.inspect}? Run `rails server --help` for more options. MSG end diff --git a/railties/lib/rails/generators.rb b/railties/lib/rails/generators.rb index f8460bd4ee..2a41403557 100644 --- a/railties/lib/rails/generators.rb +++ b/railties/lib/rails/generators.rb @@ -258,7 +258,6 @@ module Rails namespaces = Hash[subclasses.map { |klass| [klass.namespace, klass] }] lookups.each do |namespace| - klass = namespaces[namespace] return klass if klass end diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb index 34067240d7..76dbfadc0e 100644 --- a/railties/lib/rails/generators/rails/app/app_generator.rb +++ b/railties/lib/rails/generators/rails/app/app_generator.rb @@ -21,7 +21,6 @@ module Rails RUBY end - # TODO: Remove once this is fully in place def method_missing(meth, *args, &block) @generator.send(meth, *args, &block) end @@ -488,7 +487,11 @@ module Rails end def app_name - @app_name ||= (defined_app_const_base? ? defined_app_name : File.basename(destination_root)).tr('\\', "").tr(". ", "_") + @app_name ||= original_app_name.tr("-", "_") + end + + def original_app_name + @original_app_name ||= (defined_app_const_base? ? defined_app_name : File.basename(destination_root)).tr('\\', "").tr(". ", "_") end def defined_app_name @@ -513,13 +516,13 @@ module Rails def valid_const? if app_const =~ /^\d/ - raise Error, "Invalid application name #{app_name}. Please give a name which does not start with numbers." - elsif RESERVED_NAMES.include?(app_name) - raise Error, "Invalid application name #{app_name}. Please give a " \ + raise Error, "Invalid application name #{original_app_name}. Please give a name which does not start with numbers." + elsif RESERVED_NAMES.include?(original_app_name) + raise Error, "Invalid application name #{original_app_name}. Please give a " \ "name which does not match one of the reserved rails " \ "words: #{RESERVED_NAMES.join(", ")}" elsif Object.const_defined?(app_const_base) - raise Error, "Invalid application name #{app_name}, constant #{app_const_base} is already in use. Please choose another application name." + raise Error, "Invalid application name #{original_app_name}, constant #{app_const_base} is already in use. Please choose another application name." end end diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml.tt b/railties/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml.tt index 145cfb7f74..4ce4d276b7 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml.tt @@ -2,9 +2,9 @@ # # Install the pg driver: # gem install pg -# On OS X with Homebrew: +# On macOS with Homebrew: # gem install pg -- --with-pg-config=/usr/local/bin/pg_config -# On OS X with MacPorts: +# On macOS with MacPorts: # gem install pg -- --with-pg-config=/opt/local/lib/postgresql84/bin/pg_config # On Windows: # gem install pg diff --git a/railties/lib/rails/generators/rails/app/templates/ruby-version.tt b/railties/lib/rails/generators/rails/app/templates/ruby-version.tt index 19f0d7f202..bac1339923 100644 --- a/railties/lib/rails/generators/rails/app/templates/ruby-version.tt +++ b/railties/lib/rails/generators/rails/app/templates/ruby-version.tt @@ -1 +1 @@ -<%= "#{RUBY_ENGINE}-#{RUBY_ENGINE_VERSION}" -%> +<%= ENV["RBENV_VERSION"] || ENV["rvm_ruby_string"] || "#{RUBY_ENGINE}-#{RUBY_ENGINE_VERSION}" -%> diff --git a/railties/lib/rails/source_annotation_extractor.rb b/railties/lib/rails/source_annotation_extractor.rb index 7257aaeaae..2d66a4dc7d 100644 --- a/railties/lib/rails/source_annotation_extractor.rb +++ b/railties/lib/rails/source_annotation_extractor.rb @@ -8,12 +8,7 @@ SourceAnnotationExtractor = ActiveSupport::Deprecation::DeprecatedConstantProxy. new("SourceAnnotationExtractor", "Rails::SourceAnnotationExtractor") module Rails - # Implements the logic behind the rake tasks for annotations like - # - # rails notes - # rails notes:optimize - # - # and friends. See <tt>rails -T notes</tt> and <tt>railties/lib/rails/tasks/annotations.rake</tt>. + # Implements the logic behind <tt>Rails::Command::NotesCommand</tt>. See <tt>rails notes --help</tt> for usage information. # # Annotation objects are triplets <tt>:line</tt>, <tt>:tag</tt>, <tt>:text</tt> that # represent the line where the annotation lives, its tag, and its text. Note @@ -25,7 +20,7 @@ module Rails class SourceAnnotationExtractor class Annotation < Struct.new(:line, :tag, :text) def self.directories - @@directories ||= %w(app config db lib test) + (ENV["SOURCE_ANNOTATION_DIRECTORIES"] || "").split(",") + @@directories ||= %w(app config db lib test) end # Registers additional directories to be included @@ -59,15 +54,19 @@ module Rails s << "[#{tag}] " if options[:tag] s << text end + + # Used in annotations.rake + #:nodoc: + def self.notes_task_deprecation_warning + ActiveSupport::Deprecation.warn("This rake task is deprecated and will be removed in Rails 6.1. \nRefer to `rails notes --help` for more information.\n") + puts "\n" + end end # Prints all annotations with tag +tag+ under the root directories +app+, # +config+, +db+, +lib+, and +test+ (recursively). # - # Additional directories may be added using a comma-delimited list set using - # <tt>ENV['SOURCE_ANNOTATION_DIRECTORIES']</tt>. - # - # Directories may also be explicitly set using the <tt>:dirs</tt> key in +options+. + # Specific directories can be explicitly set using the <tt>:dirs</tt> key in +options+. # # Rails::SourceAnnotationExtractor.enumerate 'TODO|FIXME', dirs: %w(app lib), tag: true # @@ -75,7 +74,7 @@ module Rails # # See <tt>#find_in</tt> for a list of file extensions that will be taken into account. # - # This class method is the single entry point for the rake tasks. + # This class method is the single entry point for the `rails notes` command. def self.enumerate(tag, options = {}) extractor = new(tag) dirs = options.delete(:dirs) || Annotation.directories diff --git a/railties/lib/rails/tasks/annotations.rake b/railties/lib/rails/tasks/annotations.rake index 60bcdc5e1b..65af778a15 100644 --- a/railties/lib/rails/tasks/annotations.rake +++ b/railties/lib/rails/tasks/annotations.rake @@ -2,21 +2,21 @@ require "rails/source_annotation_extractor" -desc "Enumerate all annotations (use notes:optimize, :fixme, :todo for focus)" task :notes do - Rails::SourceAnnotationExtractor.enumerate "OPTIMIZE|FIXME|TODO", tag: true + Rails::SourceAnnotationExtractor::Annotation.notes_task_deprecation_warning + Rails::Command.invoke :notes end namespace :notes do ["OPTIMIZE", "FIXME", "TODO"].each do |annotation| - # desc "Enumerate all #{annotation} annotations" task annotation.downcase.intern do - Rails::SourceAnnotationExtractor.enumerate annotation + Rails::SourceAnnotationExtractor::Annotation.notes_task_deprecation_warning + Rails::Command.invoke :notes, ["--annotations", annotation] end end - desc "Enumerate a custom annotation, specify with ANNOTATION=CUSTOM" task :custom do - Rails::SourceAnnotationExtractor.enumerate ENV["ANNOTATION"] + Rails::SourceAnnotationExtractor::Annotation.notes_task_deprecation_warning + Rails::Command.invoke :notes, ["--annotations", ENV["ANNOTATION"]] end end diff --git a/railties/lib/rails/tasks/log.rake b/railties/lib/rails/tasks/log.rake index e219277d23..ec56957204 100644 --- a/railties/lib/rails/tasks/log.rake +++ b/railties/lib/rails/tasks/log.rake @@ -1,7 +1,6 @@ # frozen_string_literal: true namespace :log do - ## # Truncates all/specified log files # ENV['LOGS'] diff --git a/railties/lib/rails/templates/rails/welcome/index.html.erb b/railties/lib/rails/templates/rails/welcome/index.html.erb index 5a82bf913c..b6823457c0 100644 --- a/railties/lib/rails/templates/rails/welcome/index.html.erb +++ b/railties/lib/rails/templates/rails/welcome/index.html.erb @@ -62,7 +62,7 @@ <h1>Yay! You’re on Rails!</h1> - <img alt="Welcome" class="welcome" src="data:image/jpg;base64,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" /> + <img alt="Welcome" class="welcome" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABIIAAAMGCAIAAAABcbh7AAAAA3NCSVQICAjb4U/gAAAAinpUWHRSYXcgcHJvZmlsZSB0eXBlIGV4aWYAAHjaVY7RDcMwCET/PUVGwIAPGKeKEqkbdPxAnNbq+4DTyXqmHZ/32baiEzcd5giAEg0NfmVwmghRZ+q1c06eLT0Tr7oJz4BwI10P9em/DIHjNDXDwI6d086HsHjNFJWV6oxYEudbmd/+94T7th/tAkOgLCrTUorzAAAKCGlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNC40LjAtRXhpdjIiPgogPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgeG1sbnM6ZXhpZj0iaHR0cDovL25zLmFkb2JlLmNvbS9leGlmLzEuMC8iCiAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyIKICAgZXhpZjpQaXhlbFhEaW1lbnNpb249IjExNTQiCiAgIGV4aWY6UGl4ZWxZRGltZW5zaW9uPSI3NzQiCiAgIHRpZmY6SW1hZ2VXaWR0aD0iMTE1NCIKICAgdGlmZjpJbWFnZUhlaWdodD0iNzc0IgogICB0aWZmOk9yaWVudGF0aW9uPSIxIi8+CiA8L3JkZjpSREY+CjwveDp4bXBtZXRhPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg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" /> <p class="version"> <strong>Rails version:</strong> <%= Rails.version %><br /> diff --git a/railties/lib/rails/test_help.rb b/railties/lib/rails/test_help.rb index 4bd7d74b04..4e3ec184be 100644 --- a/railties/lib/rails/test_help.rb +++ b/railties/lib/rails/test_help.rb @@ -20,28 +20,29 @@ if defined?(ActiveRecord::Base) exit 1 end - module ActiveSupport - class TestCase - include ActiveRecord::TestDatabases - include ActiveRecord::TestFixtures - self.fixture_path = "#{Rails.root}/test/fixtures/" - self.file_fixture_path = fixture_path + "files" - end + ActiveSupport.on_load(:active_support_test_case) do + include ActiveRecord::TestDatabases + include ActiveRecord::TestFixtures + + self.fixture_path = "#{Rails.root}/test/fixtures/" + self.file_fixture_path = fixture_path + "files" end - ActionDispatch::IntegrationTest.fixture_path = ActiveSupport::TestCase.fixture_path + ActiveSupport.on_load(:action_dispatch_integration_test) do + self.fixture_path = ActiveSupport::TestCase.fixture_path + end end # :enddoc: -class ActionController::TestCase +ActiveSupport.on_load(:action_controller_test_case) do def before_setup # :nodoc: @routes = Rails.application.routes super end end -class ActionDispatch::IntegrationTest +ActiveSupport.on_load(:action_dispatch_integration_test) do def before_setup # :nodoc: @routes = Rails.application.routes super diff --git a/railties/test/app_loader_test.rb b/railties/test/app_loader_test.rb index c7a6bdee1b..93ed68fabb 100644 --- a/railties/test/app_loader_test.rb +++ b/railties/test/app_loader_test.rb @@ -76,7 +76,7 @@ class AppLoaderTest < ActiveSupport::TestCase # Compare the realpath in case either of them has symlinks. # - # This happens in particular in Mac OS X, where @tmp starts + # This happens in particular in macOS, where @tmp starts # with "/var", and Dir.pwd with "/private/var", due to a # default system symlink var -> private/var. assert_equal File.realpath("#@tmp/foo"), File.realpath(Dir.pwd) diff --git a/railties/test/application/per_request_digest_cache_test.rb b/railties/test/application/per_request_digest_cache_test.rb index 10d3313f6e..ab055c7648 100644 --- a/railties/test/application/per_request_digest_cache_test.rb +++ b/railties/test/application/per_request_digest_cache_test.rb @@ -5,11 +5,9 @@ require "rack/test" require "minitest/mock" require "action_view" -require "active_support/testing/method_call_assertions" class PerRequestDigestCacheTest < ActiveSupport::TestCase include ActiveSupport::Testing::Isolation - include ActiveSupport::Testing::MethodCallAssertions include Rack::Test::Methods setup do diff --git a/railties/test/application/rake/notes_test.rb b/railties/test/application/rake/notes_test.rb index d73e5cdfa3..999155fa93 100644 --- a/railties/test/application/rake/notes_test.rb +++ b/railties/test/application/rake/notes_test.rb @@ -87,6 +87,9 @@ module ApplicationTests assert_equal 6, lines.size assert_equal [4], lines.map(&:size).uniq + + log = File.read(Rails.application.config.paths["log"].first) + assert_match(/`SOURCE_ANNOTATION_DIRECTORIES` is deprecated/, log) end end diff --git a/railties/test/commands/credentials_test.rb b/railties/test/commands/credentials_test.rb index 663ee73bcd..fc16b8194f 100644 --- a/railties/test/commands/credentials_test.rb +++ b/railties/test/commands/credentials_test.rb @@ -49,7 +49,7 @@ class Rails::Command::CredentialsCommandTest < ActiveSupport::TestCase FileUtils.rm("config/master.key") switch_env("RAILS_MASTER_KEY", key) do - run_edit_command + assert_match(/access_key_id: 123/, run_edit_command) assert_not File.exist?("config/master.key") end end diff --git a/railties/test/commands/notes_test.rb b/railties/test/commands/notes_test.rb new file mode 100644 index 0000000000..147019e299 --- /dev/null +++ b/railties/test/commands/notes_test.rb @@ -0,0 +1,128 @@ +# frozen_string_literal: true + +require "isolation/abstract_unit" +require "rails/command" +require "rails/commands/notes/notes_command" + +class Rails::Command::NotesTest < ActiveSupport::TestCase + setup :build_app + teardown :teardown_app + + test "`rails notes` displays results for default directories and default annotations with aligned line number and annotation tag" do + app_file "app/controllers/some_controller.rb", "# OPTIMIZE: note in app directory" + app_file "config/initializers/some_initializer.rb", "# TODO: note in config directory" + app_file "db/some_seeds.rb", "# FIXME: note in db directory" + app_file "lib/some_file.rb", "# TODO: note in lib directory" + app_file "test/some_test.rb", "\n" * 100 + "# FIXME: note in test directory" + + app_file "some_other_dir/blah.rb", "# TODO: note in some_other directory" + + assert_equal <<~OUTPUT, run_notes_command + app/controllers/some_controller.rb: + * [ 1] [OPTIMIZE] note in app directory + + config/initializers/some_initializer.rb: + * [ 1] [TODO] note in config directory + + db/some_seeds.rb: + * [ 1] [FIXME] note in db directory + + lib/some_file.rb: + * [ 1] [TODO] note in lib directory + + test/some_test.rb: + * [101] [FIXME] note in test directory + + OUTPUT + end + + test "`rails notes` displays an empty string when no results were found" do + assert_equal "", run_notes_command + end + + test "`rails notes --annotations` displays results for a single annotation without being prefixed by a tag" do + app_file "db/some_seeds.rb", "# FIXME: note in db directory" + app_file "test/some_test.rb", "# FIXME: note in test directory" + + app_file "app/controllers/some_controller.rb", "# OPTIMIZE: note in app directory" + app_file "config/initializers/some_initializer.rb", "# TODO: note in config directory" + + assert_equal <<~OUTPUT, run_notes_command(["--annotations", "FIXME"]) + db/some_seeds.rb: + * [1] note in db directory + + test/some_test.rb: + * [1] note in test directory + + OUTPUT + end + + test "`rails notes --annotations` displays results for multiple annotations being prefixed by a tag" do + app_file "app/controllers/some_controller.rb", "# FOOBAR: note in app directory" + app_file "config/initializers/some_initializer.rb", "# TODO: note in config directory" + app_file "lib/some_file.rb", "# TODO: note in lib directory" + + app_file "test/some_test.rb", "# FIXME: note in test directory" + + assert_equal <<~OUTPUT, run_notes_command(["--annotations", "FOOBAR", "TODO"]) + app/controllers/some_controller.rb: + * [1] [FOOBAR] note in app directory + + config/initializers/some_initializer.rb: + * [1] [TODO] note in config directory + + lib/some_file.rb: + * [1] [TODO] note in lib directory + + OUTPUT + end + + test "displays results from additional directories added to the default directories from a config file" do + app_file "db/some_seeds.rb", "# FIXME: note in db directory" + app_file "lib/some_file.rb", "# TODO: note in lib directory" + app_file "spec/spec_helper.rb", "# TODO: note in spec" + app_file "spec/models/user_spec.rb", "# TODO: note in model spec" + + add_to_config "config.annotations.register_directories \"spec\"" + + assert_equal <<~OUTPUT, run_notes_command + db/some_seeds.rb: + * [1] [FIXME] note in db directory + + lib/some_file.rb: + * [1] [TODO] note in lib directory + + spec/models/user_spec.rb: + * [1] [TODO] note in model spec + + spec/spec_helper.rb: + * [1] [TODO] note in spec + + OUTPUT + end + + test "displays results from additional file extensions added to the default extensions from a config file" do + add_to_config "config.assets.precompile = []" + add_to_config %q{ config.annotations.register_extensions("scss", "sass") { |annotation| /\/\/\s*(#{annotation}):?\s*(.*)$/ } } + app_file "db/some_seeds.rb", "# FIXME: note in db directory" + app_file "app/assets/stylesheets/application.css.scss", "// TODO: note in scss" + app_file "app/assets/stylesheets/application.css.sass", "// TODO: note in sass" + + assert_equal <<~OUTPUT, run_notes_command + app/assets/stylesheets/application.css.sass: + * [1] [TODO] note in sass + + app/assets/stylesheets/application.css.scss: + * [1] [TODO] note in scss + + db/some_seeds.rb: + * [1] [FIXME] note in db directory + + OUTPUT + end + + private + def run_notes_command(args = []) + rails "notes", args + end +end diff --git a/railties/test/commands/server_test.rb b/railties/test/commands/server_test.rb index e7a56b3e6d..e5b1da6ea4 100644 --- a/railties/test/commands/server_test.rb +++ b/railties/test/commands/server_test.rb @@ -143,10 +143,22 @@ class Rails::Command::ServerCommandTest < ActiveSupport::TestCase options = parse_arguments(args) assert_equal true, options[:log_stdout] + args = ["-e", "development", "-d"] + options = parse_arguments(args) + assert_equal false, options[:log_stdout] + args = ["-e", "production"] options = parse_arguments(args) assert_equal false, options[:log_stdout] + args = ["-e", "development", "--no-log-to-stdout"] + options = parse_arguments(args) + assert_equal false, options[:log_stdout] + + args = ["-e", "production", "--log-to-stdout"] + options = parse_arguments(args) + assert_equal true, options[:log_stdout] + with_rack_env "development" do args = [] options = parse_arguments(args) @@ -245,10 +257,9 @@ class Rails::Command::ServerCommandTest < ActiveSupport::TestCase args = %w(-p 4567 -b 127.0.0.1 -c dummy_config.ru -d -e test -P tmp/server.pid -C) ARGV.replace args - options = parse_arguments(args) - expected = "bin/rails server -p 4567 -b 127.0.0.1 -c dummy_config.ru -d -e test -P tmp/server.pid -C --restart" + expected = "bin/rails server -p 4567 -b 127.0.0.1 -c dummy_config.ru -d -e test -P tmp/server.pid -C --restart" - assert_equal expected, options[:restart_cmd] + assert_equal expected, parse_arguments(args)[:restart_cmd] ensure ARGV.replace original_args end diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb index 3cb7d66bbb..b0f958091c 100644 --- a/railties/test/generators/app_generator_test.rb +++ b/railties/test/generators/app_generator_test.rb @@ -438,6 +438,30 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_file "config/application.rb", /\s+config\.load_defaults 5\.1/ end + def test_app_update_does_not_change_app_name_when_app_name_is_hyphenated_name + app_root = File.join(destination_root, "hyphenated-app") + run_generator [app_root, "-d", "postgresql"] + + assert_file "#{app_root}/config/database.yml" do |content| + assert_match(/hyphenated_app_development/, content) + assert_no_match(/hyphenated-app_development/, content) + end + + assert_file "#{app_root}/config/cable.yml" do |content| + assert_match(/hyphenated_app/, content) + assert_no_match(/hyphenated-app/, content) + end + + FileUtils.cd(app_root) do + quietly { system("bin/rails app:update") } + end + + assert_file "#{app_root}/config/cable.yml" do |content| + assert_match(/hyphenated_app/, content) + assert_no_match(/hyphenated-app/, content) + end + end + def test_application_names_are_not_singularized run_generator [File.join(destination_root, "hats")] assert_file "hats/config/environment.rb", /Rails\.application\.initialize!/ @@ -891,7 +915,13 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_match(/ruby '#{RUBY_VERSION}'/, content) end assert_file ".ruby-version" do |content| - assert_match(/#{RUBY_ENGINE}-#{RUBY_ENGINE_VERSION}/, content) + if ENV["RBENV_VERSION"] + assert_match(/#{ENV["RBENV_VERSION"]}/, content) + elsif ENV["rvm_ruby_string"] + assert_match(/#{ENV["rvm_ruby_string"]}/, content) + else + assert_match(/#{RUBY_ENGINE}-#{RUBY_ENGINE_VERSION}/, content) + end end end diff --git a/railties/test/generators_test.rb b/railties/test/generators_test.rb index a16a2d3f0a..f98c1f78f7 100644 --- a/railties/test/generators_test.rb +++ b/railties/test/generators_test.rb @@ -49,12 +49,6 @@ class GeneratorsTest < Rails::Generators::TestCase I18n.default_locale = orig_default_locale end - def test_generator_multiple_suggestions - name = :tas - output = capture(:stdout) { Rails::Generators.invoke name } - assert_match 'Maybe you meant "task"?', output - end - def test_help_when_a_generator_with_required_arguments_is_invoked_without_arguments output = capture(:stdout) { Rails::Generators.invoke :model, [] } assert_match(/Description:/, output) diff --git a/railties/test/isolation/abstract_unit.rb b/railties/test/isolation/abstract_unit.rb index 3cde7c03b0..516c457e48 100644 --- a/railties/test/isolation/abstract_unit.rb +++ b/railties/test/isolation/abstract_unit.rb @@ -14,6 +14,7 @@ require "bundler/setup" unless defined?(Bundler) require "active_support" require "active_support/testing/autorun" require "active_support/testing/stream" +require "active_support/testing/method_call_assertions" require "active_support/test_case" RAILS_FRAMEWORK_ROOT = File.expand_path("../../..", __dir__) @@ -430,6 +431,7 @@ class ActiveSupport::TestCase include TestHelpers::Rack include TestHelpers::Generation include ActiveSupport::Testing::Stream + include ActiveSupport::Testing::MethodCallAssertions def frozen_error_class Object.const_defined?(:FrozenError) ? FrozenError : RuntimeError diff --git a/railties/test/railties/engine_test.rb b/railties/test/railties/engine_test.rb index 9a3ddc8d5e..4ac8f8d741 100644 --- a/railties/test/railties/engine_test.rb +++ b/railties/test/railties/engine_test.rb @@ -570,7 +570,6 @@ YAML get("/arunagw") assert_equal "arunagw", last_response.body - end test "it provides routes as default endpoint" do |