diff options
59 files changed, 635 insertions, 499 deletions
diff --git a/.codeclimate.yml b/.codeclimate.yml index 7fd35d8241..139ee8013b 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -23,7 +23,7 @@ checks: engines: rubocop: enabled: true - channel: rubocop-0-58 + channel: rubocop-0-60 ratings: paths: diff --git a/.rubocop.yml b/.rubocop.yml index 615a229432..033f7adf49 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -133,9 +133,6 @@ Style/FrozenStringLiteralComment: Style/RedundantFreeze: Enabled: true - Exclude: - - 'actionpack/lib/action_dispatch/journey/router/utils.rb' - - 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb' # Use `foo {}` not `foo{}`. Layout/SpaceBeforeBlockBraces: @@ -104,8 +104,6 @@ group :test do platforms :mri do gem "stackprof" gem "byebug" - # FIXME: Remove this when thor 0.21 is release - gem "thor", git: "https://github.com/erikhuda/thor.git", ref: "006832ea32480618791f89bb7d9e67b22fc814b9" end gem "benchmark-ips" diff --git a/Gemfile.lock b/Gemfile.lock index 1321436814..f4f3e430ba 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,11 +1,4 @@ GIT - remote: https://github.com/erikhuda/thor.git - revision: 006832ea32480618791f89bb7d9e67b22fc814b9 - ref: 006832ea32480618791f89bb7d9e67b22fc814b9 - specs: - thor (0.20.0) - -GIT remote: https://github.com/matthewd/rb-inotify.git revision: 856730aad4b285969e8dd621e44808a7c5af4242 branch: close-handling @@ -32,9 +25,9 @@ GIT GIT remote: https://github.com/rails/webpacker.git - revision: 48d9fd52c3e9637dbb21e551b48c84c0f2dbb2ed + revision: bb132d591da35095e3246082cba3d693f847e0b5 specs: - webpacker (4.0.0.pre.pre.2) + webpacker (4.0.0.pre.3) activesupport (>= 4.2) rack-proxy (>= 0.6.1) railties (>= 4.2) @@ -105,16 +98,16 @@ PATH GEM remote: https://rubygems.org/ specs: - activerecord-jdbc-adapter (52.0-java) + activerecord-jdbc-adapter (52.1-java) activerecord (~> 5.2.0) - activerecord-jdbcmysql-adapter (52.0-java) - activerecord-jdbc-adapter (= 52.0) + activerecord-jdbcmysql-adapter (52.1-java) + activerecord-jdbc-adapter (= 52.1) jdbc-mysql (~> 5.1.36) - activerecord-jdbcpostgresql-adapter (52.0-java) - activerecord-jdbc-adapter (= 52.0) + activerecord-jdbcpostgresql-adapter (52.1-java) + activerecord-jdbc-adapter (= 52.1) jdbc-postgres (>= 9.4, < 43) - activerecord-jdbcsqlite3-adapter (52.0-java) - activerecord-jdbc-adapter (= 52.0) + activerecord-jdbcsqlite3-adapter (52.1-java) + activerecord-jdbc-adapter (= 52.1) jdbc-sqlite3 (~> 3.8, < 3.30) addressable (2.5.2) public_suffix (>= 2.0.2, < 4.0) @@ -123,17 +116,17 @@ GEM io-like (~> 0.3.0) ast (2.4.0) aws-eventstream (1.0.1) - aws-partitions (1.102.0) - aws-sdk-core (3.25.0) + aws-partitions (1.111.0) + aws-sdk-core (3.37.0) aws-eventstream (~> 1.0) aws-partitions (~> 1.0) aws-sigv4 (~> 1.0) jmespath (~> 1.0) - aws-sdk-kms (1.7.0) - aws-sdk-core (~> 3) + aws-sdk-kms (1.11.0) + aws-sdk-core (~> 3, >= 3.26.0) aws-sigv4 (~> 1.0) - aws-sdk-s3 (1.17.1) - aws-sdk-core (~> 3, >= 3.21.2) + aws-sdk-s3 (1.23.1) + aws-sdk-core (~> 3, >= 3.26.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.0) aws-sigv4 (1.0.3) @@ -173,38 +166,38 @@ GEM childprocess faraday selenium-webdriver - bootsnap (1.3.1) + bootsnap (1.3.2) msgpack (~> 1.0) - bootsnap (1.3.1-java) + bootsnap (1.3.2-java) msgpack (~> 1.0) builder (3.2.3) bunny (2.9.2) amq-protocol (~> 2.3.0) byebug (10.0.2) - capybara (3.7.1) + capybara (3.10.1) addressable mini_mime (>= 0.1.3) nokogiri (~> 1.8) rack (>= 1.6.0) rack-test (>= 0.6.3) - xpath (~> 3.1) + regexp_parser (~> 1.2) + xpath (~> 3.2) childprocess (0.9.0) ffi (~> 1.0, >= 1.0.11) - chromedriver-helper (2.0.0) + chromedriver-helper (2.1.0) archive-zip (~> 0.10) nokogiri (~> 1.8) coffee-script (2.4.1) coffee-script-source execjs coffee-script-source (1.12.2) - concurrent-ruby (1.0.5) - concurrent-ruby (1.0.5-java) + concurrent-ruby (1.1.3) connection_pool (2.2.2) cookiejar (0.3.3) crass (1.0.4) curses (1.0.2) daemons (1.2.6) - dalli (2.7.8) + dalli (2.7.9) dante (0.2.0) declarative (0.0.10) declarative-option (0.1.0) @@ -228,7 +221,7 @@ GEM event_emitter (0.2.6) eventmachine (1.2.7) execjs (2.7.0) - faraday (0.15.2) + faraday (0.15.3) multipart-post (>= 1.2, < 3) faraday_middleware (0.12.2) faraday (>= 0.7.4, < 1.0) @@ -252,39 +245,39 @@ GEM raabro (~> 1.1) globalid (0.4.1) activesupport (>= 4.2.0) - google-api-client (0.23.8) + google-api-client (0.25.0) addressable (~> 2.5, >= 2.5.1) googleauth (>= 0.5, < 0.7.0) httpclient (>= 2.8.1, < 3.0) mime-types (~> 3.0) representable (~> 3.0) retriable (>= 2.0, < 4.0) - signet (~> 0.9) - google-cloud-core (1.2.3) + signet (~> 0.10) + google-cloud-core (1.2.7) google-cloud-env (~> 1.0) - google-cloud-env (1.0.2) + google-cloud-env (1.0.5) faraday (~> 0.11) - google-cloud-storage (1.13.1) + google-cloud-storage (1.15.0) digest-crc (~> 0.4) google-api-client (~> 0.23) google-cloud-core (~> 1.2) googleauth (~> 0.6.2) - googleauth (0.6.6) + googleauth (0.6.7) faraday (~> 0.12) jwt (>= 1.4, < 3.0) - memoist (~> 0.12) + memoist (~> 0.16) multi_json (~> 1.11) os (>= 0.9, < 2.0) signet (~> 0.7) - hiredis (0.6.1) - hiredis (0.6.1-java) + hiredis (0.6.3) + hiredis (0.6.3-java) http_parser.rb (0.6.0) httpclient (2.8.3) - i18n (1.1.0) + i18n (1.1.1) concurrent-ruby (~> 1.0) - image_processing (1.6.0) + image_processing (1.7.1) mini_magick (~> 4.0) - ruby-vips (>= 2.0.11, < 3) + ruby-vips (>= 2.0.13, < 3) io-like (0.3.0) jaro_winkler (1.5.1) jaro_winkler (1.5.1-java) @@ -303,7 +296,7 @@ GEM rb-fsevent (~> 0.9, >= 0.9.4) rb-inotify (~> 0.9, >= 0.9.7) ruby_dep (~> 1.2) - loofah (2.2.2) + loofah (2.2.3) crass (~> 1.0.2) nokogiri (>= 1.5.9) mail (2.7.1) @@ -311,7 +304,7 @@ GEM marcel (0.3.3) mimemagic (~> 0.3.2) memoist (0.16.0) - method_source (0.9.0) + method_source (0.9.1) mime-types (3.2.2) mime-types-data (~> 3.2015) mime-types-data (3.2018.0812) @@ -334,7 +327,7 @@ GEM msgpack (1.2.4-x86-mingw32) multi_json (1.13.1) multipart-post (2.0.0) - mustache (1.0.5) + mustache (1.1.0) mustermann (1.0.3) mysql2 (0.5.2) mysql2 (0.5.2-x64-mingw32) @@ -350,14 +343,14 @@ GEM mini_portile2 (~> 2.3.0) os (1.0.0) parallel (1.12.1) - parser (2.5.1.2) + parser (2.5.3.0) ast (~> 2.4.0) path_expander (1.0.3) pg (1.1.3) pg (1.1.3-x64-mingw32) pg (1.1.3-x86-mingw32) powerpack (0.1.2) - psych (3.0.2) + psych (3.0.3) public_suffix (3.0.3) puma (3.12.0) puma (3.12.0-java) @@ -367,10 +360,10 @@ GEM thor raabro (1.1.6) racc (1.4.14) - rack (2.0.5) + rack (2.0.6) rack-cache (1.8.0) rack (>= 0.4) - rack-protection (2.0.3) + rack-protection (2.0.4) rack rack-proxy (0.6.5) rack @@ -386,9 +379,10 @@ GEM rb-fsevent (0.10.3) rdoc (6.0.4) redcarpet (3.2.3) - redis (4.0.2) + redis (4.0.3) redis-namespace (1.6.0) redis (>= 3.0.4) + regexp_parser (1.2.0) representable (3.0.4) declarative (< 0.1.0) declarative-option (< 0.2.0) @@ -405,14 +399,14 @@ GEM resque (~> 1.26) rufus-scheduler (~> 3.2) retriable (3.1.2) - rubocop (0.58.2) + rubocop (0.60.0) jaro_winkler (~> 1.5.1) parallel (~> 1.10) parser (>= 2.5, != 2.5.1.1) powerpack (~> 0.1) rainbow (>= 2.2.2, < 4.0) ruby-progressbar (~> 1.7) - unicode-display_width (~> 1.0, >= 1.0.1) + unicode-display_width (~> 1.4.0) ruby-progressbar (1.10.0) ruby-vips (2.0.13) ffi (~> 1.9) @@ -420,7 +414,7 @@ GEM rubyzip (1.2.2) rufus-scheduler (3.5.2) fugit (~> 1.1, >= 1.1.5) - sass (3.5.7) + sass (3.7.2) sass-listen (~> 4.0.0) sass-listen (4.0.0) rb-fsevent (~> 0.9, >= 0.9.4) @@ -433,26 +427,26 @@ GEM tilt (>= 1.1, < 3) sdoc (1.0.0) rdoc (>= 5.0) - selenium-webdriver (3.14.0) + selenium-webdriver (3.141.0) childprocess (~> 0.5) - rubyzip (~> 1.2) - sequel (5.12.0) + rubyzip (~> 1.2, >= 1.2.2) + sequel (5.14.0) serverengine (2.0.7) sigdump (~> 0.2.2) - sidekiq (5.2.1) + sidekiq (5.2.3) connection_pool (~> 2.2, >= 2.2.2) rack-protection (>= 1.5.0) redis (>= 3.3.5, < 5) sigdump (0.2.4) - signet (0.9.1) + signet (0.11.0) addressable (~> 2.3) faraday (~> 0.9) jwt (>= 1.5, < 3.0) multi_json (~> 1.10) - sinatra (2.0.3) + sinatra (2.0.4) mustermann (~> 1.0) rack (~> 2.0) - rack-protection (= 2.0.3) + rack-protection (= 2.0.4) tilt (~> 2.0) sneakers (2.7.0) bunny (~> 2.9.2) @@ -477,6 +471,7 @@ GEM daemons (~> 1.0, >= 1.0.9) eventmachine (~> 1.0, >= 1.0.4) rack (>= 1, < 3) + thor (0.20.3) thread_safe (0.3.6) thread_safe (0.3.6-java) tilt (2.0.8) @@ -485,10 +480,10 @@ GEM turbolinks-source (5.2.0) tzinfo (1.2.5) thread_safe (~> 0.1) - tzinfo-data (1.2018.5) + tzinfo-data (1.2018.7) tzinfo (>= 1.0.0) uber (0.1.0) - uglifier (4.1.18) + uglifier (4.1.19) execjs (>= 0.3.0, < 3) unicode-display_width (1.4.0) useragent (0.16.10) @@ -504,7 +499,7 @@ GEM websocket-driver (0.7.0-java) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.3) - xpath (3.1.0) + xpath (3.2.0) nokogiri (~> 1.8) PLATFORMS @@ -569,7 +564,6 @@ DEPENDENCIES sqlite3 (~> 1.3.6) stackprof sucker_punch - thor! turbolinks (~> 5) tzinfo-data uglifier (>= 1.3.0) @@ -579,4 +573,4 @@ DEPENDENCIES websocket-client-simple! BUNDLED WITH - 1.16.6 + 1.17.1 diff --git a/actioncable/actioncable.gemspec b/actioncable/actioncable.gemspec index 137fa64431..31c6fb41f2 100644 --- a/actioncable/actioncable.gemspec +++ b/actioncable/actioncable.gemspec @@ -25,6 +25,9 @@ Gem::Specification.new do |s| "changelog_uri" => "https://github.com/rails/rails/blob/v#{version}/actioncable/CHANGELOG.md" } + # NOTE: Please read our dependency guidelines before updating versions: + # https://edgeguides.rubyonrails.org/security.html#dependency-management-and-cves + s.add_dependency "actionpack", version s.add_dependency "nio4r", "~> 2.0" diff --git a/actionmailer/actionmailer.gemspec b/actionmailer/actionmailer.gemspec index f2fb160bdd..6f8d6d0699 100644 --- a/actionmailer/actionmailer.gemspec +++ b/actionmailer/actionmailer.gemspec @@ -26,6 +26,9 @@ Gem::Specification.new do |s| "changelog_uri" => "https://github.com/rails/rails/blob/v#{version}/actionmailer/CHANGELOG.md" } + # NOTE: Please read our dependency guidelines before updating versions: + # https://edgeguides.rubyonrails.org/security.html#dependency-management-and-cves + s.add_dependency "actionpack", version s.add_dependency "actionview", version s.add_dependency "activejob", version diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md index 5554d4e6b8..81201795d4 100644 --- a/actionpack/CHANGELOG.md +++ b/actionpack/CHANGELOG.md @@ -3,9 +3,9 @@ There is no controller instance when using a redirect route or a mounted rack application so pass the request object as the context when resolving dynamic CSP sources in this scenario. - + Fixes #34200. - + *Andrew White* * Apply mapping to symbols returned from dynamic CSP sources @@ -14,7 +14,7 @@ would be converted to a string implicity, e.g: policy.default_src -> { :self } - + would generate the header: Content-Security-Policy: default-src self diff --git a/actionpack/actionpack.gemspec b/actionpack/actionpack.gemspec index 1dc8abf746..ec56de18f1 100644 --- a/actionpack/actionpack.gemspec +++ b/actionpack/actionpack.gemspec @@ -26,6 +26,9 @@ Gem::Specification.new do |s| "changelog_uri" => "https://github.com/rails/rails/blob/v#{version}/actionpack/CHANGELOG.md" } + # NOTE: Please read our dependency guidelines before updating versions: + # https://edgeguides.rubyonrails.org/security.html#dependency-management-and-cves + s.add_dependency "activesupport", version s.add_dependency "rack", "~> 2.0" diff --git a/actionview/CHANGELOG.md b/actionview/CHANGELOG.md index fd8bae0cdf..1f537e725a 100644 --- a/actionview/CHANGELOG.md +++ b/actionview/CHANGELOG.md @@ -11,7 +11,7 @@ *Eileen M. Uchitelle*, *Aaron Patterson* * Respect the `only_path` option passed to `url_for` when the options are passed in as an array - + Fixes #33237. *Joel Ambass* diff --git a/actionview/actionview.gemspec b/actionview/actionview.gemspec index 49ee1a292b..5f1e746421 100644 --- a/actionview/actionview.gemspec +++ b/actionview/actionview.gemspec @@ -26,6 +26,9 @@ Gem::Specification.new do |s| "changelog_uri" => "https://github.com/rails/rails/blob/v#{version}/actionview/CHANGELOG.md" } + # NOTE: Please read our dependency guidelines before updating versions: + # https://edgeguides.rubyonrails.org/security.html#dependency-management-and-cves + s.add_dependency "activesupport", version s.add_dependency "builder", "~> 3.1" diff --git a/activejob/activejob.gemspec b/activejob/activejob.gemspec index be6292f737..cd7ac210ec 100644 --- a/activejob/activejob.gemspec +++ b/activejob/activejob.gemspec @@ -25,6 +25,9 @@ Gem::Specification.new do |s| "changelog_uri" => "https://github.com/rails/rails/blob/v#{version}/activejob/CHANGELOG.md" } + # NOTE: Please read our dependency guidelines before updating versions: + # https://edgeguides.rubyonrails.org/security.html#dependency-management-and-cves + s.add_dependency "activesupport", version s.add_dependency "globalid", ">= 0.3.6" end diff --git a/activejob/lib/active_job/arguments.rb b/activejob/lib/active_job/arguments.rb index 31347194d2..a86a82c6e3 100644 --- a/activejob/lib/active_job/arguments.rb +++ b/activejob/lib/active_job/arguments.rb @@ -62,7 +62,7 @@ module ActiveJob OBJECT_SERIALIZER_KEY, OBJECT_SERIALIZER_KEY.to_sym, WITH_INDIFFERENT_ACCESS_KEY, WITH_INDIFFERENT_ACCESS_KEY.to_sym, ] - private_constant :RESERVED_KEYS + private_constant :RESERVED_KEYS, :GLOBALID_KEY, :SYMBOL_KEYS_KEY, :WITH_INDIFFERENT_ACCESS_KEY def serialize_argument(argument) case argument diff --git a/activemodel/activemodel.gemspec b/activemodel/activemodel.gemspec index 7be466dc4c..493fca698a 100644 --- a/activemodel/activemodel.gemspec +++ b/activemodel/activemodel.gemspec @@ -25,5 +25,8 @@ Gem::Specification.new do |s| "changelog_uri" => "https://github.com/rails/rails/blob/v#{version}/activemodel/CHANGELOG.md" } + # NOTE: Please read our dependency guidelines before updating versions: + # https://edgeguides.rubyonrails.org/security.html#dependency-management-and-cves + s.add_dependency "activesupport", version end diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 9d80bbe51f..2a237f86cf 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,30 @@ +* Add an `:if_not_exists` option to `create_table`. + + Example: + + create_table :posts, if_not_exists: true do |t| + t.string :title + end + + That would execute: + + CREATE TABLE IF NOT EXISTS posts ( + ... + ) + + If the table already exists, `if_not_exists: false` (the default) raises an + exception whereas `if_not_exists: true` does nothing. + + *fatkodima*, *Stefan Kanev* + +* Defining an Enum as a Hash with blank key, or as an Array with a blank value, now raises an `ArgumentError`. + + *Christophe Maximin* + +* Adds support for multiple databases to `rails db:schema:cache:dump` and `rails db:schema:cache:clear`. + + *Gannon McGibbon* + * `update_columns` now correctly raises `ActiveModel::MissingAttributeError` if the attribute does not exist. diff --git a/activerecord/activerecord.gemspec b/activerecord/activerecord.gemspec index a857d00c05..bcdd82052c 100644 --- a/activerecord/activerecord.gemspec +++ b/activerecord/activerecord.gemspec @@ -28,6 +28,9 @@ Gem::Specification.new do |s| "changelog_uri" => "https://github.com/rails/rails/blob/v#{version}/activerecord/CHANGELOG.md" } + # NOTE: Please read our dependency guidelines before updating versions: + # https://edgeguides.rubyonrails.org/security.html#dependency-management-and-cves + s.add_dependency "activesupport", version s.add_dependency "activemodel", version end diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb index 1e92ee3b96..fd8c1da842 100644 --- a/activerecord/lib/active_record/attribute_methods.rb +++ b/activerecord/lib/active_record/attribute_methods.rb @@ -328,7 +328,7 @@ module ActiveRecord # person.attribute_for_inspect(:tag_ids) # # => "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]" def attribute_for_inspect(attr_name) - value = read_attribute(attr_name) + value = _read_attribute(attr_name) format_for_inspect(value) end diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb index 9d9e8a4110..19ff780192 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb @@ -39,7 +39,9 @@ module ActiveRecord end def visit_TableDefinition(o) - create_sql = +"CREATE#{' TEMPORARY' if o.temporary} TABLE #{quote_table_name(o.name)} " + create_sql = +"CREATE#{' TEMPORARY' if o.temporary} TABLE " + create_sql << "IF NOT EXISTS " if o.if_not_exists + create_sql << "#{quote_table_name(o.name)} " statements = o.columns.map { |c| accept c } statements << accept(o.primary_keys) if o.primary_keys 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 70607fda5a..db489143af 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +require "active_support/deprecation" + module ActiveRecord module ConnectionAdapters #:nodoc: # Abstract representation of an index definition on a table. Instances of @@ -256,15 +258,25 @@ module ActiveRecord class TableDefinition include ColumnMethods - attr_accessor :indexes - attr_reader :name, :temporary, :options, :as, :foreign_keys, :comment + attr_reader :name, :temporary, :if_not_exists, :options, :as, :comment, :indexes, :foreign_keys + attr_writer :indexes + deprecate :indexes= - def initialize(name, temporary = false, options = nil, as = nil, comment: nil) + def initialize( + name, + temporary: false, + if_not_exists: false, + options: nil, + as: nil, + comment: nil, + ** + ) @columns_hash = {} @indexes = [] @foreign_keys = [] @primary_keys = nil @temporary = temporary + @if_not_exists = if_not_exists @options = options @as = as @name = name diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb index 8a7020a799..38cfc3a241 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -205,6 +205,9 @@ module ActiveRecord # Set to true to drop the table before creating it. # Set to +:cascade+ to drop dependent objects as well. # Defaults to false. + # [<tt>:if_not_exists</tt>] + # Set to true to avoid raising an error when the table already exists. + # Defaults to false. # [<tt>:as</tt>] # SQL to use to generate the table. When this option is used, the block is # ignored, as are the <tt>:id</tt> and <tt>:primary_key</tt> options. @@ -287,8 +290,8 @@ module ActiveRecord # SELECT * FROM orders INNER JOIN line_items ON order_id=orders.id # # See also TableDefinition#column for details on how to create columns. - def create_table(table_name, comment: nil, **options) - td = create_table_definition table_name, options[:temporary], options[:options], options[:as], comment: comment + def create_table(table_name, **options) + td = create_table_definition(table_name, options) if options[:id] != false && !options[:as] pk = options.fetch(:primary_key) do @@ -317,7 +320,9 @@ module ActiveRecord end if supports_comments? && !supports_comments_in_create? - change_table_comment(table_name, comment) if comment.present? + if table_comment = options[:comment].presence + change_table_comment(table_name, table_comment) + end td.columns.each do |column| change_column_comment(table_name, column.name, column.comment) if column.comment.present? diff --git a/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb b/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb index 564b226b39..0f2b1e85ff 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb @@ -137,7 +137,7 @@ module ActiveRecord record.committed! else # if not running callbacks, only adds the record to the parent transaction - record.add_to_transaction + connection.add_transaction_record(record) end end ensure diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb index e75202b0be..0895d06356 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb @@ -93,11 +93,11 @@ module ActiveRecord elsif value.hex? "X'#{value}'" end - when Float - if value.infinite? || value.nan? - "'#{value}'" - else + when Numeric + if value.finite? super + else + "'#{value}'" end when OID::Array::Data _quote(encode_array(value)) diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb index da3e2549a2..50f3087c51 100644 --- a/activerecord/lib/active_record/core.rb +++ b/activerecord/lib/active_record/core.rb @@ -498,7 +498,7 @@ module ActiveRecord inspection = if defined?(@attributes) && @attributes self.class.attribute_names.collect do |name| if has_attribute?(name) - attr = read_attribute(name) + attr = _read_attribute(name) value = if attr.nil? attr.inspect else @@ -528,7 +528,7 @@ module ActiveRecord pp.text attr_name pp.text ":" pp.breakable - value = read_attribute(attr_name) + value = _read_attribute(attr_name) value = inspection_filter.filter_param(attr_name, value) unless value.nil? pp.pp value end diff --git a/activerecord/lib/active_record/enum.rb b/activerecord/lib/active_record/enum.rb index 3d97e4e513..3a600835e1 100644 --- a/activerecord/lib/active_record/enum.rb +++ b/activerecord/lib/active_record/enum.rb @@ -218,6 +218,10 @@ module ActiveRecord MSG raise ArgumentError, error_message end + + if values.is_a?(Hash) && values.keys.any?(&:blank?) || values.is_a?(Array) && values.any?(&:blank?) + raise ArgumentError, "Enum label name must not be blank." + end end ENUM_CONFLICT_MESSAGE = \ diff --git a/activerecord/lib/active_record/fixture_set/model_metadata.rb b/activerecord/lib/active_record/fixture_set/model_metadata.rb index edc03939c8..fb23df6f45 100644 --- a/activerecord/lib/active_record/fixture_set/model_metadata.rb +++ b/activerecord/lib/active_record/fixture_set/model_metadata.rb @@ -3,9 +3,8 @@ module ActiveRecord class FixtureSet class ModelMetadata # :nodoc: - def initialize(model_class, table_name) + def initialize(model_class) @model_class = model_class - @table_name = table_name end def primary_key_name @@ -23,18 +22,12 @@ module ActiveRecord def timestamp_column_names @timestamp_column_names ||= - %w(created_at created_on updated_at updated_on) & column_names + %w(created_at created_on updated_at updated_on) & @model_class.column_names end def inheritance_column_name @inheritance_column_name ||= @model_class && @model_class.inheritance_column end - - private - - def column_names - @column_names ||= @model_class.connection.columns(@table_name).collect(&:name) - end end end end diff --git a/activerecord/lib/active_record/fixture_set/table_row.rb b/activerecord/lib/active_record/fixture_set/table_row.rb index 5f72c1df38..cb4726f1ee 100644 --- a/activerecord/lib/active_record/fixture_set/table_row.rb +++ b/activerecord/lib/active_record/fixture_set/table_row.rb @@ -3,6 +3,38 @@ module ActiveRecord class FixtureSet class TableRow # :nodoc: + class ReflectionProxy # :nodoc: + def initialize(association) + @association = association + end + + def join_table + @association.join_table + end + + def name + @association.name + end + + def primary_key_type + @association.klass.type_for_attribute(@association.klass.primary_key).type + end + end + + class HasManyThroughProxy < ReflectionProxy # :nodoc: + def rhs_key + @association.foreign_key + end + + def lhs_key + @association.through_reflection.foreign_key + end + + def join_table + @association.through_reflection.table_name + end + end + def initialize(fixture, table_rows:, label:, now:) @table_rows = table_rows @label = label @@ -31,7 +63,7 @@ module ActiveRecord interpolate_label generate_primary_key resolve_enums - @table_rows.resolve_sti_reflections(@row) + resolve_sti_reflections end def reflection_class @@ -74,6 +106,48 @@ module ActiveRecord end end end + + def resolve_sti_reflections + # If STI is used, find the correct subclass for association reflection + reflection_class._reflections.each_value do |association| + case association.macro + when :belongs_to + # Do not replace association name with association foreign key if they are named the same + fk_name = (association.options[:foreign_key] || "#{association.name}_id").to_s + + if association.name.to_s != fk_name && value = @row.delete(association.name.to_s) + if association.polymorphic? && value.sub!(/\s*\(([^\)]*)\)\s*$/, "") + # support polymorphic belongs_to as "label (Type)" + @row[association.foreign_type] = $1 + end + + fk_type = reflection_class.type_for_attribute(fk_name).type + @row[fk_name] = ActiveRecord::FixtureSet.identify(value, fk_type) + end + when :has_many + if association.options[:through] + add_join_records(HasManyThroughProxy.new(association)) + end + end + end + end + + def add_join_records(association) + # This is the case when the join table has no fixtures file + if (targets = @row.delete(association.name.to_s)) + table_name = association.join_table + column_type = association.primary_key_type + lhs_key = association.lhs_key + rhs_key = association.rhs_key + + targets = targets.is_a?(Array) ? targets : targets.split(/\s*,\s*/) + joins = targets.map do |target| + { lhs_key => @row[model_metadata.primary_key_name], + rhs_key => ActiveRecord::FixtureSet.identify(target, column_type) } + end + @table_rows.tables[table_name].concat(joins) + end + end end end end diff --git a/activerecord/lib/active_record/fixture_set/table_rows.rb b/activerecord/lib/active_record/fixture_set/table_rows.rb index 3e3c0bc7ab..23814b6cb5 100644 --- a/activerecord/lib/active_record/fixture_set/table_rows.rb +++ b/activerecord/lib/active_record/fixture_set/table_rows.rb @@ -6,40 +6,7 @@ require "active_record/fixture_set/model_metadata" module ActiveRecord class FixtureSet class TableRows # :nodoc: - class ReflectionProxy # :nodoc: - def initialize(association) - @association = association - end - - def join_table - @association.join_table - end - - def name - @association.name - end - - def primary_key_type - @association.klass.type_for_attribute(@association.klass.primary_key).type - end - end - - class HasManyThroughProxy < ReflectionProxy # :nodoc: - def rhs_key - @association.foreign_key - end - - def lhs_key - @association.through_reflection.foreign_key - end - - def join_table - @association.through_reflection.table_name - end - end - def initialize(table_name, model_class:, fixtures:, config:) - @table_name = table_name @model_class = model_class # track any join tables we need to insert later @@ -48,49 +15,22 @@ module ActiveRecord # ensure this table is loaded before any HABTM associations @tables[table_name] = nil - build_table_rows_from(fixtures, config) + build_table_rows_from(table_name, fixtures, config) end - attr_reader :table_name, :model_class + attr_reader :tables, :model_class def to_hash @tables.transform_values { |rows| rows.map(&:to_hash) } end def model_metadata - @model_metadata ||= ModelMetadata.new(model_class, table_name) - end - - def resolve_sti_reflections(row) - # If STI is used, find the correct subclass for association reflection - reflection_class = reflection_class_for(row) - - reflection_class._reflections.each_value do |association| - case association.macro - when :belongs_to - # Do not replace association name with association foreign key if they are named the same - fk_name = (association.options[:foreign_key] || "#{association.name}_id").to_s - - if association.name.to_s != fk_name && value = row.delete(association.name.to_s) - if association.polymorphic? && value.sub!(/\s*\(([^\)]*)\)\s*$/, "") - # support polymorphic belongs_to as "label (Type)" - row[association.foreign_type] = $1 - end - - fk_type = reflection_class.type_for_attribute(fk_name).type - row[fk_name] = ActiveRecord::FixtureSet.identify(value, fk_type) - end - when :has_many - if association.options[:through] - add_join_records(row, HasManyThroughProxy.new(association)) - end - end - end + @model_metadata ||= ModelMetadata.new(model_class) end private - def build_table_rows_from(fixtures, config) + def build_table_rows_from(table_name, fixtures, config) now = config.default_timezone == :utc ? Time.now.utc : Time.now @tables[table_name] = fixtures.map do |label, fixture| @@ -102,31 +42,6 @@ module ActiveRecord ) end end - - def reflection_class_for(row) - if row.include?(model_metadata.inheritance_column_name) - row[model_metadata.inheritance_column_name].constantize rescue model_class - else - model_class - end - end - - def add_join_records(row, association) - # This is the case when the join table has no fixtures file - if (targets = row.delete(association.name.to_s)) - table_name = association.join_table - column_type = association.primary_key_type - lhs_key = association.lhs_key - rhs_key = association.rhs_key - - targets = targets.is_a?(Array) ? targets : targets.split(/\s*,\s*/) - joins = targets.map do |target| - { lhs_key => row[model_metadata.primary_key_name], - rhs_key => ActiveRecord::FixtureSet.identify(target, column_type) } - end - @tables[table_name].concat(joins) - end - end end end end diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb index b090c76a38..1248ed00c5 100644 --- a/activerecord/lib/active_record/fixtures.rb +++ b/activerecord/lib/active_record/fixtures.rb @@ -577,9 +577,8 @@ module ActiveRecord fixtures_map = {} fixture_sets = fixture_files.map do |fixture_set_name| klass = class_names[fixture_set_name] - conn = klass&.connection || connection fixtures_map[fixture_set_name] = new( # ActiveRecord::FixtureSet.new - conn, + nil, fixture_set_name, klass, ::File.join(fixtures_directory, fixture_set_name) @@ -621,7 +620,7 @@ module ActiveRecord attr_reader :table_name, :name, :fixtures, :model_class, :config - def initialize(connection, name, class_name, path, config = ActiveRecord::Base) + def initialize(_, name, class_name, path, config = ActiveRecord::Base) @name = name @path = path @config = config @@ -630,11 +629,7 @@ module ActiveRecord @fixtures = read_fixture_files(path) - @connection = connection - - @table_name = (model_class.respond_to?(:table_name) ? - model_class.table_name : - self.class.default_fixture_table_name(name, config)) + @table_name = model_class&.table_name || self.class.default_fixture_table_name(name, config) end def [](x) diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake index 1c7ceb4981..475baa7559 100644 --- a/activerecord/lib/active_record/railties/databases.rake +++ b/activerecord/lib/active_record/railties/databases.rake @@ -300,15 +300,22 @@ db_namespace = namespace :db do namespace :cache do desc "Creates a db/schema_cache.yml file." task dump: :load_config do - conn = ActiveRecord::Base.connection - filename = File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, "schema_cache.yml") - ActiveRecord::Tasks::DatabaseTasks.dump_schema_cache(conn, filename) + ActiveRecord::Base.configurations.configs_for(env_name: Rails.env).each do |db_config| + ActiveRecord::Base.establish_connection(db_config.config) + filename = ActiveRecord::Tasks::DatabaseTasks.cache_dump_filename(db_config.spec_name) + ActiveRecord::Tasks::DatabaseTasks.dump_schema_cache( + ActiveRecord::Base.connection, + filename, + ) + end end desc "Clears a db/schema_cache.yml file." task clear: :load_config do - filename = File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, "schema_cache.yml") - rm_f filename, verbose: false + ActiveRecord::Base.configurations.configs_for(env_name: Rails.env).each do |db_config| + filename = ActiveRecord::Tasks::DatabaseTasks.cache_dump_filename(db_config.spec_name) + rm_f filename, verbose: false + end end end end diff --git a/activerecord/lib/active_record/tasks/database_tasks.rb b/activerecord/lib/active_record/tasks/database_tasks.rb index 974d7a1c0a..27e401a756 100644 --- a/activerecord/lib/active_record/tasks/database_tasks.rb +++ b/activerecord/lib/active_record/tasks/database_tasks.rb @@ -313,6 +313,16 @@ module ActiveRecord ENV["SCHEMA"] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, filename) end + def cache_dump_filename(namespace) + filename = if namespace == "primary" + "schema_cache.yml" + else + "#{namespace}_schema_cache.yml" + end + + ENV["SCHEMA_CACHE"] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, filename) + end + def load_schema_current(format = ActiveRecord::Base.schema_format, file = nil, environment = env) each_current_configuration(environment) { |configuration, spec_name, env| load_schema(configuration, format, file, env, spec_name) diff --git a/activerecord/test/cases/attribute_methods_test.rb b/activerecord/test/cases/attribute_methods_test.rb index 6c2e256447..0dbdd56ae6 100644 --- a/activerecord/test/cases/attribute_methods_test.rb +++ b/activerecord/test/cases/attribute_methods_test.rb @@ -56,6 +56,13 @@ class AttributeMethodsTest < ActiveRecord::TestCase assert_equal "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]", t.attribute_for_inspect(:content) end + test "attribute_for_inspect with a non-primary key id attribute" do + t = topics(:first).becomes(TitlePrimaryKeyTopic) + t.title = "The First Topic Now Has A Title With\nNewlines And More Than 50 Characters" + + assert_equal "1", t.attribute_for_inspect(:id) + end + test "attribute_present" do t = Topic.new t.title = "hello there!" diff --git a/activerecord/test/cases/core_test.rb b/activerecord/test/cases/core_test.rb index f7fbf3ee8a..36e3d543cd 100644 --- a/activerecord/test/cases/core_test.rb +++ b/activerecord/test/cases/core_test.rb @@ -30,6 +30,11 @@ class CoreTest < ActiveRecord::TestCase assert_equal %(#<Topic id: 1, title: "The First Topic">), Topic.all.merge!(select: "id, title", where: "id = 1").first.inspect end + def test_inspect_instance_with_non_primary_key_id_attribute + topic = topics(:first).becomes(TitlePrimaryKeyTopic) + assert_match(/id: 1/, topic.inspect) + end + def test_inspect_class_without_table assert_equal "NonExistentTable(Table doesn't exist)", NonExistentTable.inspect end @@ -110,4 +115,11 @@ class CoreTest < ActiveRecord::TestCase PP.pp(subtopic.new, StringIO.new(actual)) assert_equal "inspecting topic\n", actual end + + def test_pretty_print_with_non_primary_key_id_attribute + topic = topics(:first).becomes(TitlePrimaryKeyTopic) + actual = +"" + PP.pp(topic, StringIO.new(actual)) + assert_match(/id: 1/, actual) + end end diff --git a/activerecord/test/cases/enum_test.rb b/activerecord/test/cases/enum_test.rb index b4593ccdf2..867ce7082b 100644 --- a/activerecord/test/cases/enum_test.rb +++ b/activerecord/test/cases/enum_test.rb @@ -274,6 +274,24 @@ class EnumTest < ActiveRecord::TestCase end assert_match(/must be either a hash, an array of symbols, or an array of strings./, e.message) + + e = assert_raises(ArgumentError) do + Class.new(ActiveRecord::Base) do + self.table_name = "books" + enum status: { "" => 1, "active" => 2 } + end + end + + assert_match(/Enum label name must not be blank/, e.message) + + e = assert_raises(ArgumentError) do + Class.new(ActiveRecord::Base) do + self.table_name = "books" + enum status: ["active", ""] + end + end + + assert_match(/Enum label name must not be blank/, e.message) end test "reserved enum names" do diff --git a/activerecord/test/cases/fixtures_test.rb b/activerecord/test/cases/fixtures_test.rb index 1092b9553f..a5592fc86a 100644 --- a/activerecord/test/cases/fixtures_test.rb +++ b/activerecord/test/cases/fixtures_test.rb @@ -473,11 +473,11 @@ class FixturesTest < ActiveRecord::TestCase end def test_empty_yaml_fixture - assert_not_nil ActiveRecord::FixtureSet.new(Account.connection, "accounts", Account, FIXTURES_ROOT + "/naked/yml/accounts") + assert_not_nil ActiveRecord::FixtureSet.new(nil, "accounts", Account, FIXTURES_ROOT + "/naked/yml/accounts") end def test_empty_yaml_fixture_with_a_comment_in_it - assert_not_nil ActiveRecord::FixtureSet.new(Account.connection, "companies", Company, FIXTURES_ROOT + "/naked/yml/companies") + assert_not_nil ActiveRecord::FixtureSet.new(nil, "companies", Company, FIXTURES_ROOT + "/naked/yml/companies") end def test_nonexistent_fixture_file @@ -487,14 +487,14 @@ class FixturesTest < ActiveRecord::TestCase assert_empty Dir[nonexistent_fixture_path + "*"] assert_raise(Errno::ENOENT) do - ActiveRecord::FixtureSet.new(Account.connection, "companies", Company, nonexistent_fixture_path) + ActiveRecord::FixtureSet.new(nil, "companies", Company, nonexistent_fixture_path) end end def test_dirty_dirty_yaml_file fixture_path = FIXTURES_ROOT + "/naked/yml/courses" error = assert_raise(ActiveRecord::Fixture::FormatError) do - ActiveRecord::FixtureSet.new(Account.connection, "courses", Course, fixture_path) + ActiveRecord::FixtureSet.new(nil, "courses", Course, fixture_path) end assert_equal "fixture is not a hash: #{fixture_path}.yml", error.to_s end @@ -502,7 +502,7 @@ class FixturesTest < ActiveRecord::TestCase def test_yaml_file_with_one_invalid_fixture fixture_path = FIXTURES_ROOT + "/naked/yml/courses_with_invalid_key" error = assert_raise(ActiveRecord::Fixture::FormatError) do - ActiveRecord::FixtureSet.new(Account.connection, "courses", Course, fixture_path) + ActiveRecord::FixtureSet.new(nil, "courses", Course, fixture_path) end assert_equal "fixture key is not a hash: #{fixture_path}.yml, keys: [\"two\"]", error.to_s end @@ -525,7 +525,7 @@ class FixturesTest < ActiveRecord::TestCase def test_omap_fixtures assert_nothing_raised do - fixtures = ActiveRecord::FixtureSet.new(Account.connection, "categories", Category, FIXTURES_ROOT + "/categories_ordered") + fixtures = ActiveRecord::FixtureSet.new(nil, "categories", Category, FIXTURES_ROOT + "/categories_ordered") fixtures.each.with_index do |(name, fixture), i| assert_equal "fixture_no_#{i}", name @@ -596,7 +596,7 @@ class HasManyThroughFixture < ActiveRecord::TestCase parrots = File.join FIXTURES_ROOT, "parrots" - fs = ActiveRecord::FixtureSet.new parrot.connection, "parrots", parrot, parrots + fs = ActiveRecord::FixtureSet.new(nil, "parrots", parrot, parrots) rows = fs.table_rows assert_equal load_has_and_belongs_to_many["parrots_treasures"], rows["parrots_treasures"] end @@ -614,7 +614,7 @@ class HasManyThroughFixture < ActiveRecord::TestCase parrots = File.join FIXTURES_ROOT, "parrots" - fs = ActiveRecord::FixtureSet.new parrot.connection, "parrots", parrot, parrots + fs = ActiveRecord::FixtureSet.new(nil, "parrots", parrot, parrots) rows = fs.table_rows assert_equal load_has_and_belongs_to_many["parrots_treasures"], rows["parrot_treasures"] end @@ -629,7 +629,7 @@ class HasManyThroughFixture < ActiveRecord::TestCase parrots = File.join FIXTURES_ROOT, "parrots" - fs = ActiveRecord::FixtureSet.new parrot.connection, "parrots", parrot, parrots + fs = ActiveRecord::FixtureSet.new(nil, "parrots", parrot, parrots) fs.table_rows end end diff --git a/activerecord/test/cases/hot_compatibility_test.rb b/activerecord/test/cases/hot_compatibility_test.rb index e7778af55b..7b388ebc5e 100644 --- a/activerecord/test/cases/hot_compatibility_test.rb +++ b/activerecord/test/cases/hot_compatibility_test.rb @@ -56,7 +56,7 @@ class HotCompatibilityTest < ActiveRecord::TestCase assert_equal "bar", record.foo end - if current_adapter?(:PostgreSQLAdapter) + if current_adapter?(:PostgreSQLAdapter) && ActiveRecord::Base.connection.prepared_statements test "cleans up after prepared statement failure in a transaction" do with_two_connections do |original_connection, ddl_connection| record = @klass.create! bar: "bar" diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb index 5d060c8899..661163b4a1 100644 --- a/activerecord/test/cases/migration_test.rb +++ b/activerecord/test/cases/migration_test.rb @@ -127,6 +127,36 @@ class MigrationTest < ActiveRecord::TestCase assert_equal 20131219224947, migrator.current_version end + def test_create_table_raises_if_already_exists + connection = Person.connection + connection.create_table :testings, force: true do |t| + t.string :foo + end + + assert_raise(ActiveRecord::StatementInvalid) do + connection.create_table :testings do |t| + t.string :foo + end + end + ensure + connection.drop_table :testings, if_exists: true + end + + def test_create_table_with_if_not_exists_true + connection = Person.connection + connection.create_table :testings, force: true do |t| + t.string :foo + end + + assert_nothing_raised do + connection.create_table :testings, if_not_exists: true do |t| + t.string :foo + end + end + ensure + connection.drop_table :testings, if_exists: true + end + def test_create_table_with_force_true_does_not_drop_nonexisting_table # using a copy as we need the drop_table method to # continue to work for the ensure block of the test diff --git a/activerecord/test/cases/numeric_data_test.rb b/activerecord/test/cases/numeric_data_test.rb index 14db63890e..304714979c 100644 --- a/activerecord/test/cases/numeric_data_test.rb +++ b/activerecord/test/cases/numeric_data_test.rb @@ -25,7 +25,6 @@ class NumericDataTest < ActiveRecord::TestCase assert m.save m1 = NumericData.find(m.id) - assert_not_nil m1 assert_kind_of Integer, m1.world_population assert_equal 2**62, m1.world_population @@ -50,7 +49,6 @@ class NumericDataTest < ActiveRecord::TestCase assert m.save m1 = NumericData.find(m.id) - assert_not_nil m1 assert_kind_of Integer, m1.world_population assert_equal 2**62, m1.world_population @@ -64,4 +62,26 @@ class NumericDataTest < ActiveRecord::TestCase assert_kind_of BigDecimal, m1.big_bank_balance assert_equal BigDecimal("234000567.95"), m1.big_bank_balance end + + if current_adapter?(:PostgreSQLAdapter) + def test_numeric_fields_with_nan + m = NumericData.new( + bank_balance: BigDecimal("NaN"), + big_bank_balance: BigDecimal("NaN"), + world_population: 2**62, + my_house_population: 3 + ) + assert_predicate m.bank_balance, :nan? + assert_predicate m.big_bank_balance, :nan? + assert m.save + + m1 = NumericData.find_by( + bank_balance: BigDecimal("NaN"), + big_bank_balance: BigDecimal("NaN") + ) + + assert_predicate m1.bank_balance, :nan? + assert_predicate m1.big_bank_balance, :nan? + end + end end diff --git a/activerecord/test/cases/transaction_callbacks_test.rb b/activerecord/test/cases/transaction_callbacks_test.rb index c0be45eee7..aa6b7915a2 100644 --- a/activerecord/test/cases/transaction_callbacks_test.rb +++ b/activerecord/test/cases/transaction_callbacks_test.rb @@ -591,6 +591,17 @@ class TransactionEnrollmentCallbacksTest < ActiveRecord::TestCase assert_equal [:before_commit, :after_commit], @topic.history end + def test_commit_run_transactions_callbacks_with_nested_transactions + @topic.transaction do + @topic.transaction(requires_new: true) do + @topic.content = "foo" + @topic.save! + @topic.class.connection.add_transaction_record(@topic) + end + end + assert_equal [:before_commit, :after_commit], @topic.history + end + def test_rollback_does_not_run_transactions_callbacks_without_enrollment @topic.transaction do @topic.content = "foo" diff --git a/activerecord/test/models/topic.rb b/activerecord/test/models/topic.rb index 4aad6a4498..03430154db 100644 --- a/activerecord/test/models/topic.rb +++ b/activerecord/test/models/topic.rb @@ -138,6 +138,10 @@ class BlankTopic < Topic end end +class TitlePrimaryKeyTopic < Topic + self.primary_key = :title +end + module Web class Topic < ActiveRecord::Base has_many :replies, dependent: :destroy, foreign_key: "parent_id", class_name: "Web::Reply" diff --git a/activestorage/activestorage.gemspec b/activestorage/activestorage.gemspec index cb1bb00a25..2c8816df25 100644 --- a/activestorage/activestorage.gemspec +++ b/activestorage/activestorage.gemspec @@ -25,6 +25,9 @@ Gem::Specification.new do |s| "changelog_uri" => "https://github.com/rails/rails/blob/v#{version}/activestorage/CHANGELOG.md" } + # NOTE: Please read our dependency guidelines before updating versions: + # https://edgeguides.rubyonrails.org/security.html#dependency-management-and-cves + s.add_dependency "actionpack", version s.add_dependency "activerecord", version diff --git a/activesupport/activesupport.gemspec b/activesupport/activesupport.gemspec index aa695c98b2..448a2eeebb 100644 --- a/activesupport/activesupport.gemspec +++ b/activesupport/activesupport.gemspec @@ -27,6 +27,9 @@ Gem::Specification.new do |s| "changelog_uri" => "https://github.com/rails/rails/blob/v#{version}/activesupport/CHANGELOG.md" } + # NOTE: Please read our dependency guidelines before updating versions: + # https://edgeguides.rubyonrails.org/security.html#dependency-management-and-cves + s.add_dependency "i18n", ">= 0.7", "< 2" s.add_dependency "tzinfo", "~> 1.1" s.add_dependency "minitest", "~> 5.1" diff --git a/activesupport/lib/active_support/testing/parallelization.rb b/activesupport/lib/active_support/testing/parallelization.rb index c03a07873d..9c8dffa9d8 100644 --- a/activesupport/lib/active_support/testing/parallelization.rb +++ b/activesupport/lib/active_support/testing/parallelization.rb @@ -79,7 +79,14 @@ module ActiveSupport reporter = job[2] result = Minitest.run_one_method(klass, method) - queue.record(reporter, result) + begin + queue.record(reporter, result) + rescue DRb::DRbConnError + result.failures.each do |failure| + failure.exception = DRb::DRbRemoteError.new(failure.exception) + end + queue.record(reporter, result) + end end ensure run_cleanup(worker) diff --git a/guides/source/active_record_validations.md b/guides/source/active_record_validations.md index c98f24d786..0fda7c5cfd 100644 --- a/guides/source/active_record_validations.md +++ b/guides/source/active_record_validations.md @@ -538,7 +538,8 @@ end If you want to be sure that an association is present, you'll need to test whether the associated object itself is present, and not the foreign key used -to map the association. +to map the association. This way, it is not only checked that the foreign key +is not empty but also that the referenced object exists. ```ruby class LineItem < ApplicationRecord diff --git a/guides/source/contributing_to_ruby_on_rails.md b/guides/source/contributing_to_ruby_on_rails.md index ed47a0de0f..709a5146e9 100644 --- a/guides/source/contributing_to_ruby_on_rails.md +++ b/guides/source/contributing_to_ruby_on_rails.md @@ -324,6 +324,26 @@ $ cd actionmailer $ bundle exec rake test ``` +#### For a Specific Directory + +If you want to run the tests located in a specific directory use the `TEST_DIR` +environment variable. For example, this will run the tests in the +`railties/test/generators` directory only: + +```bash +$ cd railties +$ TEST_DIR=generators bundle exec rake test +``` + +#### For a Specific File + +You can run the tests for a particular file by using: + +```bash +$ cd actionpack +$ bundle exec ruby -w -Itest test/template/form_helper_test.rb +``` + #### Running a Single Test You can run a single test through ruby. For instance: @@ -333,8 +353,7 @@ $ cd actionmailer $ bundle exec ruby -w -Itest test/mail_layout_test.rb -n test_explicit_class_layout ``` -The `-n` option allows you to run a single method instead of the whole -file. +The `-n` option allows you to run a single method instead of the whole file. #### Running tests with a specific seed diff --git a/guides/source/debugging_rails_applications.md b/guides/source/debugging_rails_applications.md index 7f7766e7d7..3a383cbd4d 100644 --- a/guides/source/debugging_rails_applications.md +++ b/guides/source/debugging_rails_applications.md @@ -232,7 +232,7 @@ irb(main):003:0> Article.pamplemousse => #<Comment id: 2, author: "1", body: "Well, actually...", article_id: 1, created_at: "2018-10-19 00:56:10", updated_at: "2018-10-19 00:56:10"> ``` -Below each database statement you can see arrows pointing to the specific source filename (and line number) of the method that resulted in a database call. This can help you identity and address performance problems caused by N+1 queries: single database queries that generates multiple additional queries. +Below each database statement you can see arrows pointing to the specific source filename (and line number) of the method that resulted in a database call. This can help you identify and address performance problems caused by N+1 queries: single database queries that generates multiple additional queries. Verbose query logs are enabled by default in the development environment logs after Rails 5.2. diff --git a/guides/source/development_dependencies_install.md b/guides/source/development_dependencies_install.md index 07538a1cb7..d52946be08 100644 --- a/guides/source/development_dependencies_install.md +++ b/guides/source/development_dependencies_install.md @@ -8,8 +8,6 @@ This guide covers how to setup an environment for Ruby on Rails core development After reading this guide, you will know: * How to set up your machine for Rails development -* How to run specific groups of unit tests from the Rails test suite -* How the Active Record portion of the Rails test suite operates -------------------------------------------------------------------------------- @@ -43,195 +41,131 @@ $ git clone https://github.com/rails/rails.git $ cd rails ``` -### Set up and Run the Tests +### Install Additional Tools and Services -The test suite must pass with any submitted code. No matter whether you are writing a new patch, or evaluating someone else's, you need to be able to run the tests. +Some Rails tests depend on additional tools that you need to install before running those specific tests. -Install first SQLite3 and its development files for the `sqlite3` gem. On macOS -users are done with: +Here's the list of each gems' additional dependencies: -```bash -$ brew install sqlite3 -``` - -In Ubuntu you're done with just: - -```bash -$ sudo apt-get install sqlite3 libsqlite3-dev -``` - -If you are on Fedora or CentOS, you're done with - -```bash -$ sudo yum install libsqlite3x libsqlite3x-devel -``` - -If you are on Arch Linux, you will need to run: - -```bash -$ sudo pacman -S sqlite -``` - -For FreeBSD users, you're done with: - -```bash -# pkg install sqlite3 -``` +* Action Cable depends on Redis +* Active Record depends on SQLite3, MySQL and PostgreSQL +* Active Storage depends on Yarn (additionally Yarn depends on + [Node.js](https://nodejs.org/)), ImageMagick, FFmpeg, muPDF, and on macOS + also XQuartz and Poppler. +* Active Support depends on memcached and Redis +* Railties depend on a JavaScript runtime environment, such as having + [Node.js](https://nodejs.org/) installed. -Or compile the `databases/sqlite3` port. +Install all the services you need to properly test the full gem you'll be +making changes to. -Get a recent version of [Bundler](https://bundler.io/) +NOTE: Redis' documentation discourage installations with package managers as those are usually outdated. Installing from source and bringing the server up is straight forward and well documented on [Redis' documentation](https://redis.io/download#installation). -```bash -$ gem install bundler -$ gem update bundler -``` +NOTE: Active Record tests _must_ pass for at least MySQL, PostgreSQL, and SQLite3. Subtle differences between the various adapters have been behind the rejection of many patches that looked OK when tested only against single adapter. -and run: +Below you can find instructions on how to install all of the additional +tools for different OSes. -```bash -$ bundle install --without db -``` - -This command will install all dependencies except the MySQL and PostgreSQL Ruby drivers. We will come back to these soon. +#### macOS -NOTE: If you would like to run the tests that use memcached, you need to ensure that you have it installed and running. +On macOS you can use [Homebrew](https://brew.sh/) to install all of the +additional tools. -You can use [Homebrew](https://brew.sh/) to install memcached on macOS: +To install all run: ```bash -$ brew install memcached +$ brew bundle ``` -On Ubuntu you can install it with apt-get: +You'll also need to start each of the installed services. To list all +available services run: ```bash -$ sudo apt-get install memcached +$ brew services list ``` -Or use yum on Fedora or CentOS: +You can then start each of the services one by one like this: ```bash -$ sudo yum install memcached +$ brew services start mysql ``` -If you are running on Arch Linux: - -```bash -$ sudo pacman -S memcached -``` - -For FreeBSD users, you're done with: - -```bash -# pkg install memcached -``` +Replace `mysql` with the name of the service you want to start. -Alternatively, you can compile the `databases/memcached` port. +#### Ubuntu -With the dependencies now installed, you can run the test suite with: +To install all run: ```bash -$ bundle exec rake test -``` - -You can also run tests for a specific component, like Action Pack, by going into its directory and executing the same command: +$ sudo apt-get update +$ sudo apt-get install sqlite3 libsqlite3-dev + mysql-server libmysqlclient-dev + postgresql postgresql-client postgresql-contrib libpq-dev + redis-server memcached imagemagick ffmpeg mupdf mupdf-tools -```bash -$ cd actionpack -$ bundle exec rake test +# Install Yarn +$ curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - +$ echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list +$ sudo apt-get install yarn ``` -If you want to run the tests located in a specific directory use the `TEST_DIR` environment variable. For example, this will run the tests in the `railties/test/generators` directory only: - -```bash -$ cd railties -$ TEST_DIR=generators bundle exec rake test -``` +#### Fedora or CentOS -You can run the tests for a particular file by using: +To install all run: ```bash -$ cd actionpack -$ bundle exec ruby -Itest test/template/form_helper_test.rb -``` - -Or, you can run a single test in a particular file: +$ sudo dnf install sqlite-devel sqlite-libs + mysql-server mysql-devel + postgresql-server postgresql-devel + redis memcached imagemagick ffmpeg mupdf -```bash -$ cd actionpack -$ bundle exec ruby -Itest path/to/test.rb -n test_name +# Install Yarn +# Use this command if you do not have Node.js installed +$ curl --silent --location https://rpm.nodesource.com/setup_8.x | sudo bash - +# If you have Node.js installed, use this command instead +$ curl --silent --location https://dl.yarnpkg.com/rpm/yarn.repo | sudo tee /etc/yum.repos.d/yarn.repo +$ sudo dnf install yarn ``` -### Railties Setup - -Some Railties tests depend on a JavaScript runtime environment, such as having [Node.js](https://nodejs.org/) installed. - -### Active Record Setup - -Active Record's test suite runs three times: once for SQLite3, once for MySQL, and once for PostgreSQL. We are going to see now how to set up the environment for them. - -WARNING: If you're working with Active Record code, you _must_ ensure that the tests pass for at least MySQL, PostgreSQL, and SQLite3. Subtle differences between the various adapters have been behind the rejection of many patches that looked OK when tested only against MySQL. - -#### Database Configuration - -The Active Record test suite requires a custom config file: `activerecord/test/config.yml`. An example is provided in `activerecord/test/config.example.yml` which can be copied and used as needed for your environment. +#### Arch Linux -#### MySQL and PostgreSQL - -To be able to run the suite for MySQL and PostgreSQL we need their gems. Install -first the servers, their client libraries, and their development files. - -On macOS, you can run: - -```bash -$ brew install mysql -$ brew install postgresql -``` - -Follow the instructions given by Homebrew to start these. - -On Ubuntu, just run: - -```bash -$ sudo apt-get install mysql-server libmysqlclient-dev -$ sudo apt-get install postgresql postgresql-client postgresql-contrib libpq-dev -``` - -On Fedora or CentOS, just run: +To install all run: ```bash -$ sudo yum install mysql-server mysql-devel -$ sudo yum install postgresql-server postgresql-devel +$ sudo pacman -S sqlite + mariadb libmariadbclient mariadb-clients + postgresql postgresql-libs + redis memcached imagemagick ffmpeg mupdf mupdf-tools poppler + yarn +$ sudo systemctl start redis ``` -If you are running Arch Linux, MySQL isn't supported anymore so you will need to -use MariaDB instead (see [this announcement](https://www.archlinux.org/news/mariadb-replaces-mysql-in-repositories/)): +NOTE: If you are running Arch Linux, MySQL isn't supported anymore so you will need to +use MariaDB instead (see [this announcement](https://www.archlinux.org/news/mariadb-replaces-mysql-in-repositories/)). -```bash -$ sudo pacman -S mariadb libmariadbclient mariadb-clients -$ sudo pacman -S postgresql postgresql-libs -``` +#### FreeBSD -FreeBSD users will have to run the following: +To install all run: ```bash -# pkg install mysql56-client mysql56-server -# pkg install postgresql94-client postgresql94-server +# pkg install sqlite3 + mysql80-client mysql80-server + postgresql11-client postgresql11-server + memcached imagemagick ffmpeg mupdf + yarn +# portmaster databases/redis ``` -Or install them through ports (they are located under the `databases` folder). -If you run into troubles during the installation of MySQL, please see -[the MySQL documentation](http://dev.mysql.com/doc/refman/5.1/en/freebsd-installation.html). +Or install everyting through ports (these packages are located under the +`databases` folder). -After that, run: +NOTE: If you run into troubles during the installation of MySQL, please see +[the MySQL documentation](https://dev.mysql.com/doc/refman/8.0/en/freebsd-installation.html). -```bash -$ rm .bundle/config -$ bundle install -``` +### Database Configuration -First, we need to delete `.bundle/config` because Bundler remembers in that file that we didn't want to install the "db" group (alternatively you can edit the file). +There are couple of additional steps required to configure database engines +required for running Active Record tests. In order to be able to run the test suite against MySQL you need to create a user named `rails` with privileges on the test databases: @@ -247,13 +181,6 @@ mysql> GRANT ALL PRIVILEGES ON inexistent_activerecord_unittest.* to 'rails'@'localhost'; ``` -and create the test databases: - -```bash -$ cd activerecord -$ bundle exec rake db:mysql:build -``` - PostgreSQL's authentication works differently. To setup the development environment with your development account, on Linux or BSD, you just have to run: @@ -267,21 +194,24 @@ and for macOS: $ createuser --superuser $USER ``` -Then, you need to create the test databases with: +Then, you need to create the test databases for both MySQL and PostgreSQL with: ```bash $ cd activerecord -$ bundle exec rake db:postgresql:build +$ bundle exec rake db:create ``` -It is possible to build databases for both PostgreSQL and MySQL with: +NOTE: You'll see the following warning (or localized warning) during activating HStore extension in PostgreSQL 9.1.x or earlier: "WARNING: => is deprecated as an operator". + +You can also create test databases for each database engine separately: ```bash $ cd activerecord -$ bundle exec rake db:create +$ bundle exec rake db:mysql:build +$ bundle exec rake db:postgresql:build ``` -You can cleanup the databases using: +and you can drop the databases using: ```bash $ cd activerecord @@ -290,138 +220,40 @@ $ bundle exec rake db:drop NOTE: Using the Rake task to create the test databases ensures they have the correct character set and collation. -NOTE: You'll see the following warning (or localized warning) during activating HStore extension in PostgreSQL 9.1.x or earlier: "WARNING: => is deprecated as an operator". - If you're using another database, check the file `activerecord/test/config.yml` or `activerecord/test/config.example.yml` for default connection information. You can edit `activerecord/test/config.yml` to provide different credentials on your machine if you must, but obviously you should not push any such changes back to Rails. -### Action Cable Setup - -Action Cable uses Redis as its default subscriptions adapter ([read more](action_cable_overview.html#broadcasting)). Thus, in order to have Action Cable's tests passing you need to install and have Redis running. - -#### Install Redis From Source +### Install JavaScript dependencies -Redis' documentation discourage installations with package managers as those are usually outdated. Installing from source and bringing the server up is straight forward and well documented on [Redis' documentation](https://redis.io/download#installation). - -#### Install Redis From Package Manager - -On macOS, you can run: - -```bash -$ brew install redis -``` - -Follow the instructions given by Homebrew to start these. - -On Ubuntu, just run: - -```bash -$ sudo apt-get install redis-server -``` - -On Fedora or CentOS (requires EPEL enabled), just run: - -```bash -$ sudo yum install redis -``` - -If you are running Arch Linux, just run: - -```bash -$ sudo pacman -S redis -$ sudo systemctl start redis -``` - -FreeBSD users will have to run the following: - -```bash -# portmaster databases/redis -``` - -### Active Storage Setup - -When working on Active Storage, it is important to note that you need to -install its JavaScript dependencies while working on that section of the -codebase. In order to install these dependencies, it is necessary to -have Yarn, a Node.js package manager, available on your system. A -prerequisite for installing this package manager is that -[Node.js](https://nodejs.org) is installed. - - -On macOS, you can run: - -```bash -$ brew install yarn -``` - -On Ubuntu, you can run: - -```bash -$ curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - -$ echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list - -$ sudo apt-get update && sudo apt-get install yarn -``` - -On Fedora or CentOS, just run: - -```bash -$ sudo wget https://dl.yarnpkg.com/rpm/yarn.repo -O /etc/yum.repos.d/yarn.repo - -$ sudo yum install yarn -``` - -Finally, after installing Yarn, you will need to run the following -command inside of the `activestorage` directory to install the dependencies: +If you installed Yarn, you will need to install the javascript dependencies: ```bash +$ cd activestorage $ yarn install ``` -Extracting previews, tested in Active Storage's test suite requires third-party -applications, ImageMagick for images, FFmpeg for video and muPDF for PDFs, and on macOS also XQuartz -and Poppler. Without these applications installed, Active Storage tests will -raise errors. +### Install Bundler gem -On macOS you can run: +Get a recent version of [Bundler](https://bundler.io/) ```bash -$ brew install ffmpeg -$ brew install imagemagick -$ brew cask install xquartz -$ brew install mupdf-tools -$ brew install poppler +$ gem install bundler +$ gem update bundler ``` -On Ubuntu, you can run: +and run: ```bash -$ sudo apt-get update -$ sudo apt-get install ffmpeg -$ sudo apt-get install imagemagick -$ sudo apt-get install mupdf mupdf-tools +$ bundle install ``` -On Fedora or CentOS, just run: +or: ```bash -$ sudo yum install ffmpeg -$ sudo yum install imagemagick -$ sudo yum install mupdf +$ bundle install --without db ``` -FreeBSD users can just run: +if you don't need to run Active Record tests. -```bash -# pkg install imagemagick -# pkg install ffmpeg -# pkg install mupdf -``` - -On Arch Linux, you can run: +### Contribute to Rails -```bash -$ sudo pacman -S ffmpeg -$ sudo pacman -S imagemagick -$ sudo pacman -S mupdf mupdf-tools -$ sudo pacman -S poppler -``` +After you've setup everything, read how you can start [contributing](contributing_to_ruby_on_rails.html#running-an-application-against-your-local-branch). diff --git a/guides/source/ruby_on_rails_guides_guidelines.md b/guides/source/ruby_on_rails_guides_guidelines.md index f5c0ba5b2d..4b56cf6296 100644 --- a/guides/source/ruby_on_rails_guides_guidelines.md +++ b/guides/source/ruby_on_rails_guides_guidelines.md @@ -107,8 +107,8 @@ HTML Guides ----------- Before generating the guides, make sure that you have the latest version of -Bundler installed on your system. As of this writing, you must install Bundler -1.3.5 or later on your device. +Bundler installed on your system. You can find the latest Bundler version +[here](https://rubygems.org/gems/bundler). As of this writing, it's v1.17.1. To install the latest version of Bundler, run `gem install bundler`. diff --git a/guides/source/security.md b/guides/source/security.md index bb996cc39c..dbec3cdd2d 100644 --- a/guides/source/security.md +++ b/guides/source/security.md @@ -1235,6 +1235,11 @@ version: Rails.application.credentials.some_api_key! # => raises KeyError: :some_api_key is blank ``` +Dependency Management and CVEs +------------------------------ + +We don’t bump dependencies just to encourage use of new versions, including for security issues. This is because application owners need to manually update their gems regardless of our efforts. Use `bundle update --conservative gem_name` to safely update vulnerable dependencies. + Additional Resources -------------------- diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md index f94b67a0ac..65dccbb3be 100644 --- a/railties/CHANGELOG.md +++ b/railties/CHANGELOG.md @@ -1,3 +1,9 @@ +* Add JSON support to rails properties route (`/rails/info/properties`). + + Now, `Rails::Info` properties may be accessed in JSON format at `/rails/info/properties.json`. + + *Yoshiyuki Hirano* + * Use Ids instead of memory addresses when displaying references in scaffold views. Fixes #29200. diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/content_security_policy.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/content_security_policy.rb.tt index d3bcaa5ec8..c517b0f96b 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/content_security_policy.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/content_security_policy.rb.tt @@ -11,6 +11,10 @@ # policy.object_src :none # policy.script_src :self, :https # policy.style_src :self, :https +<%- unless options[:skip_javascript] -%> +# # If you are using webpack-dev-server then specify webpack-dev-server host +# policy.connect_src :self, :https, "http://localhost:3035", "ws://localhost:3035" if Rails.env.development? +<%- end -%> # # Specify URI for violation reports # # policy.report_uri "/csp-violation-report-endpoint" diff --git a/railties/lib/rails/generators/rails/app/templates/package.json.tt b/railties/lib/rails/generators/rails/app/templates/package.json.tt index a654cba39c..7174116989 100644 --- a/railties/lib/rails/generators/rails/app/templates/package.json.tt +++ b/railties/lib/rails/generators/rails/app/templates/package.json.tt @@ -5,7 +5,7 @@ "rails-ujs": ">=5.2.1"<% unless options[:skip_turbolinks] %>, "turbolinks": "5.1.1"<% end -%><% unless skip_active_storage? %>, "activestorage": ">=5.2.1"<% end -%><% unless options[:skip_action_cable] %>, - "actioncable": ">=5.2.1"<% end -%> + "actioncable": ">=5.2.1"<% end %> }, "version": "0.1.0" } diff --git a/railties/lib/rails/info.rb b/railties/lib/rails/info.rb index 3df36efc4c..b8173c8d11 100644 --- a/railties/lib/rails/info.rb +++ b/railties/lib/rails/info.rb @@ -54,6 +54,10 @@ module Rails table << "</table>" end end + + def to_json + Hash[properties].to_json + end end # The Rails version. diff --git a/railties/lib/rails/info_controller.rb b/railties/lib/rails/info_controller.rb index b4f4a5922a..50fe176946 100644 --- a/railties/lib/rails/info_controller.rb +++ b/railties/lib/rails/info_controller.rb @@ -14,8 +14,16 @@ class Rails::InfoController < Rails::ApplicationController # :nodoc: end def properties - @info = Rails::Info.to_html - @page_title = "Properties" + respond_to do |format| + format.html do + @info = Rails::Info.to_html + @page_title = "Properties" + end + + format.json do + render json: Rails::Info.to_json + end + end end def routes diff --git a/railties/railties.gemspec b/railties/railties.gemspec index 6fdb4648c2..4e4a504c97 100644 --- a/railties/railties.gemspec +++ b/railties/railties.gemspec @@ -30,6 +30,9 @@ Gem::Specification.new do |s| "changelog_uri" => "https://github.com/rails/rails/blob/v#{version}/railties/CHANGELOG.md" } + # NOTE: Please read our dependency guidelines before updating versions: + # https://edgeguides.rubyonrails.org/security.html#dependency-management-and-cves + s.add_dependency "activesupport", version s.add_dependency "actionpack", version diff --git a/railties/test/application/rake/multi_dbs_test.rb b/railties/test/application/rake/multi_dbs_test.rb index 6478e06250..ef99365e75 100644 --- a/railties/test/application/rake/multi_dbs_test.rb +++ b/railties/test/application/rake/multi_dbs_test.rb @@ -65,6 +65,27 @@ module ApplicationTests end end + def db_migrate_and_schema_cache_dump + Dir.chdir(app_path) do + generate_models_for_animals + rails "db:migrate" + rails "db:schema:cache:dump" + assert File.exist?("db/schema_cache.yml") + assert File.exist?("db/animals_schema_cache.yml") + end + end + + def db_migrate_and_schema_cache_dump_and_schema_cache_clear + Dir.chdir(app_path) do + generate_models_for_animals + rails "db:migrate" + rails "db:schema:cache:dump" + rails "db:schema:cache:clear" + assert_not File.exist?("db/schema_cache.yml") + assert_not File.exist?("db/animals_schema_cache.yml") + end + end + def db_migrate_and_schema_dump_and_load(format) Dir.chdir(app_path) do generate_models_for_animals @@ -92,7 +113,7 @@ module ApplicationTests end end - def db_migrate_namespaced(namespace, expected_database) + def db_migrate_namespaced(namespace) Dir.chdir(app_path) do generate_models_for_animals output = rails("db:migrate:#{namespace}") @@ -104,7 +125,7 @@ module ApplicationTests end end - def db_migrate_status_namespaced(namespace, expected_database) + def db_migrate_status_namespaced(namespace) Dir.chdir(app_path) do generate_models_for_animals output = rails("db:migrate:status:#{namespace}") @@ -178,7 +199,7 @@ module ApplicationTests test "db:migrate:namespace works" do require "#{app_path}/config/environment" ActiveRecord::Base.configurations.configs_for(env_name: Rails.env).each do |db_config| - db_migrate_namespaced db_config.spec_name, db_config.config["database"] + db_migrate_namespaced db_config.spec_name end end @@ -190,10 +211,20 @@ module ApplicationTests test "db:migrate:status:namespace works" do require "#{app_path}/config/environment" ActiveRecord::Base.configurations.configs_for(env_name: Rails.env).each do |db_config| - db_migrate_namespaced db_config.spec_name, db_config.config["database"] - db_migrate_status_namespaced db_config.spec_name, db_config.config["database"] + db_migrate_namespaced db_config.spec_name + db_migrate_status_namespaced db_config.spec_name end end + + test "db:schema:cache:dump works on all databases" do + require "#{app_path}/config/environment" + db_migrate_and_schema_cache_dump + end + + test "db:schema:cache:clear works on all databases" do + require "#{app_path}/config/environment" + db_migrate_and_schema_cache_dump_and_schema_cache_clear + end end end end diff --git a/railties/test/application/rake_test.rb b/railties/test/application/rake_test.rb index a0cdae898b..c38b91ef03 100644 --- a/railties/test/application/rake_test.rb +++ b/railties/test/application/rake_test.rb @@ -189,8 +189,10 @@ module ApplicationTests rails "generate", "model", "Product" rails "generate", "model", "Cart" rails "generate", "scaffold", "LineItems", "product:references", "cart:belongs_to" - with_rails_env("test") { rails("db:migrate") } - rails("webpacker:compile") + with_rails_env("test") do + rails("db:migrate") + rails("webpacker:compile") + end output = rails("test") assert_match(/7 runs, 9 assertions, 0 failures, 0 errors/, output) diff --git a/railties/test/application/test_runner_test.rb b/railties/test/application/test_runner_test.rb index 5c34b205c9..0046fec062 100644 --- a/railties/test/application/test_runner_test.rb +++ b/railties/test/application/test_runner_test.rb @@ -562,6 +562,30 @@ module ApplicationTests assert_no_match "create_table(:users)", output end + def test_run_in_parallel_with_unmarshable_exception + file = app_file "test/fail_test.rb", <<-RUBY + require "test_helper" + class FailTest < ActiveSupport::TestCase + class BadError < StandardError + def initialize + super + @proc = ->{ } + end + end + + test "fail" do + raise BadError + assert true + end + end + RUBY + + output = run_test_command(file) + + assert_match "DRb::DRbRemoteError: FailTest::BadError", output + assert_match "1 runs, 0 assertions, 0 failures, 1 errors", output + end + def test_raise_error_when_specified_file_does_not_exist error = capture(:stderr) { run_test_command("test/not_exists.rb", stderr: true) } assert_match(%r{cannot load such file.+test/not_exists\.rb}, error) diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb index bb3aaa9d14..32d00f3157 100644 --- a/railties/test/generators/app_generator_test.rb +++ b/railties/test/generators/app_generator_test.rb @@ -230,6 +230,14 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_equal "false\n", output end + def test_csp_initializer_include_connect_src_example + run_generator + + assert_file "config/initializers/content_security_policy.rb" do |content| + assert_match(/# policy\.connect_src/, content) + end + end + def test_app_update_keep_the_cookie_serializer_if_it_is_already_configured app_root = File.join(destination_root, "myapp") run_generator [app_root] @@ -807,6 +815,9 @@ class AppGeneratorTest < Rails::Generators::TestCase end assert_no_gem "webpacker" + assert_file "config/initializers/content_security_policy.rb" do |content| + assert_no_match(/policy\.connect_src/, content) + end end def test_webpack_option_with_js_framework diff --git a/railties/test/rails_info_controller_test.rb b/railties/test/rails_info_controller_test.rb index 878a238f8d..6ab68f8333 100644 --- a/railties/test/rails_info_controller_test.rb +++ b/railties/test/rails_info_controller_test.rb @@ -50,6 +50,11 @@ class InfoControllerTest < ActionController::TestCase assert_select "table" end + test "info controller renders json with properties" do + get :properties, format: :json + assert_equal Rails::Info.to_json, response.body + end + test "info controller renders with routes" do get :routes assert_response :success diff --git a/railties/test/rails_info_test.rb b/railties/test/rails_info_test.rb index 50522c1be6..d167a86e56 100644 --- a/railties/test/rails_info_test.rb +++ b/railties/test/rails_info_test.rb @@ -43,6 +43,18 @@ class InfoTest < ActiveSupport::TestCase end end + def test_json_includes_middleware + Rails::Info.module_eval do + property "Middleware", ["Rack::Lock", "Rack::Static"] + end + + hash = JSON.parse(Rails::Info.to_json) + assert_includes hash.keys, "Middleware" + properties.value_for("Middleware").each do |value| + assert_includes hash["Middleware"], value + end + end + private def properties Rails::Info.properties |