Commit Graph

85876 Commits

Author SHA1 Message Date
Nikita Vasilevsky 734f424247 Support composite foreign keys in associations
Foundations to support associations with composite foreign keys like:
`Comment.belongs_to :blog_post, foreign_key: [:blog_id, :blog_post_id],
primary_key: [:blog_id, :id]`
2023-01-31 17:46:41 +00:00
Jean Boussier 2e28ae403d
Merge pull request #46939 from fatkodima/fix-dumping-virtual-columns
Fix schema cache dumping of virtual columns
2023-01-10 00:23:53 +01:00
Jonathan Hefner fa11789d49
Merge pull request #46943 from jonathanhefner/hwia-default-match-hash-default-arity
Match arity of `Hash#default` in `HWIA#default`
2023-01-09 17:00:42 -06:00
Jonathan Hefner a2d179aa0c
Merge pull request #46942 from jonathanhefner/hwia-fetch_values-use-map-bang
Use `map!` in `HashWithIndifferentAccess#fetch_values`
2023-01-09 17:00:27 -06:00
Jonathan Hefner b3c01961bc
Merge pull request #46941 from jonathanhefner/hwia-values_at-use-map-bang
Use `map!` in `HashWithIndifferentAccess#values_at`
2023-01-09 17:00:13 -06:00
Jonathan Hefner 1c4f242c1f
Merge pull request #46940 from jonathanhefner/hwia-except-use-except-bang
Use `#except!` in `HashWithIndifferentAccess#except`
2023-01-09 16:59:40 -06:00
Jonathan Hefner 88269a93f3 Use map! in HashWithIndifferentAccess#fetch_values
This avoids an extra allocation from `map`.

__Benchmark__

  ```ruby
  # frozen_string_literal: true
  require "benchmark/ips"
  require "active_support/all"

  Hash.alias_method(:old_fetch_values, :fetch_values)
  Hash.alias_method(:new_fetch_values, :fetch_values)

  class ActiveSupport::HashWithIndifferentAccess
    def old_fetch_values(*indices, &block)
      super(*indices.map { |key| convert_key(key) }, &block)
    end

    def new_fetch_values(*indices, &block)
      indices.map! { |key| convert_key(key) }
      super
    end
  end

  hwia = { foo: 1, bar: 2, baz: 3, qux: 4 }.with_indifferent_access
  splat_keys = [:bar, :baz]

  Benchmark.ips do |x|
    x.report("old fetch_values 1") do
      hwia.old_fetch_values(:bar)
    end

    x.report("new fetch_values 1") do
      hwia.new_fetch_values(:bar)
    end

    x.compare!
  end

  Benchmark.ips do |x|
    x.report("old fetch_values splat") do
      hwia.old_fetch_values(*splat_keys)
    end

    x.report("new fetch_values splat") do
      hwia.new_fetch_values(*splat_keys)
    end

    x.compare!
  end
  ```

__Results__

  ```
  Warming up --------------------------------------
    old fetch_values 1   150.459k i/100ms
    new fetch_values 1   162.756k i/100ms
  Calculating -------------------------------------
    old fetch_values 1      1.503M (± 1.3%) i/s -      7.523M in   5.006517s
    new fetch_values 1      1.620M (± 1.0%) i/s -      8.138M in   5.022927s

  Comparison:
    new fetch_values 1:  1620310.5 i/s
    old fetch_values 1:  1502873.2 i/s - 1.08x  (± 0.00) slower

  Warming up --------------------------------------
  old fetch_values splat
                         109.967k i/100ms
  new fetch_values splat
                         117.143k i/100ms
  Calculating -------------------------------------
  old fetch_values splat
                            1.100M (± 1.5%) i/s -      5.498M in   5.001587s
  new fetch_values splat
                            1.168M (± 1.0%) i/s -      5.857M in   5.015409s

  Comparison:
  new fetch_values splat:  1167963.4 i/s
  old fetch_values splat:  1099558.2 i/s - 1.06x  (± 0.00) slower
  ```
2023-01-09 15:51:27 -06:00
Jonathan Hefner d8a6f35805 Use map! in HashWithIndifferentAccess#values_at
This avoids an extra allocation from `map`.

__Benchmark__

  ```ruby
  # frozen_string_literal: true
  require "benchmark/ips"
  require "active_support/all"

  Hash.alias_method(:old_values_at, :values_at)
  Hash.alias_method(:new_values_at, :values_at)

  class ActiveSupport::HashWithIndifferentAccess
    def old_values_at(*keys)
      super(*keys.map { |key| convert_key(key) })
    end

    def new_values_at(*keys)
      keys.map! { |key| convert_key(key) }
      super
    end
  end

  hwia = { foo: 1, bar: 2, baz: 3, qux: 4 }.with_indifferent_access
  splat_keys = [:bar, :baz]

  Benchmark.ips do |x|
    x.report("old values_at 1") do
      hwia.old_values_at(:bar)
    end

    x.report("new values_at 1") do
      hwia.new_values_at(:bar)
    end

    x.compare!
  end

  Benchmark.ips do |x|
    x.report("old values_at splat") do
      hwia.old_values_at(*splat_keys)
    end

    x.report("new values_at splat") do
      hwia.new_values_at(*splat_keys)
    end

    x.compare!
  end
  ```

__Results__

  ```
  Warming up --------------------------------------
       old values_at 1   150.881k i/100ms
       new values_at 1   163.731k i/100ms
  Calculating -------------------------------------
       old values_at 1      1.509M (± 1.3%) i/s -      7.695M in   5.099286s
       new values_at 1      1.646M (± 1.1%) i/s -      8.350M in   5.072959s

  Comparison:
       new values_at 1:  1646260.9 i/s
       old values_at 1:  1509283.6 i/s - 1.09x  (± 0.00) slower

  Warming up --------------------------------------
   old values_at splat   110.815k i/100ms
   new values_at splat   118.871k i/100ms
  Calculating -------------------------------------
   old values_at splat      1.118M (± 1.3%) i/s -      5.652M in   5.057480s
   new values_at splat      1.194M (± 0.9%) i/s -      6.062M in   5.077104s

  Comparison:
   new values_at splat:  1194171.4 i/s
   old values_at splat:  1117670.4 i/s - 1.07x  (± 0.00) slower
  ```
2023-01-09 15:50:35 -06:00
Jonathan Hefner c618ed8e07 Match arity of Hash#default in HWIA#default
Follow-up to b9beb3eee1.

Ruby's `Hash#default` expects 0..1 args:

  ```ruby
  {}.default(:foo, :bar)
  # => wrong number of arguments (given 2, expected 0..1) (ArgumentError)
  ```

Using a sentinel value instead of `*args` improves performance:

__Benchmark__

  ```ruby
  # frozen_string_literal: true
  require "benchmark/ips"
  require "active_support/all"

  Hash.alias_method(:old_default, :default)
  Hash.alias_method(:new_default, :default)

  class ActiveSupport::HashWithIndifferentAccess
    def old_default(*args)
      if args.length == 1
        super(convert_key(args[0]))
      else
        super(*args.map { |arg| convert_key(arg) })
      end
    end

    def new_default(key = (no_key = true))
      if no_key
        super()
      else
        super(convert_key(key))
      end
    end
  end

  hwia = {}.with_indifferent_access
  hwia.default_proc = -> (h, key) { key }

  Benchmark.ips do |x|
    x.report("old default nullary") do
      hwia.old_default
    end

    x.report("new default nullary") do
      hwia.new_default
    end

    x.compare!
  end

  Benchmark.ips do |x|
    x.report("old default unary") do
      hwia.old_default(:key)
    end

    x.report("new default unary") do
      hwia.new_default(:key)
    end

    x.compare!
  end
  ```

__Results__

  ```
  Warming up --------------------------------------
   old default nullary   266.594k i/100ms
   new default nullary   606.502k i/100ms
  Calculating -------------------------------------
   old default nullary      2.708M (± 1.3%) i/s -     13.596M in   5.022049s
   new default nullary      6.052M (± 0.5%) i/s -     30.325M in   5.011218s

  Comparison:
   new default nullary:  6051595.4 i/s
   old default nullary:  2707813.7 i/s - 2.23x  (± 0.00) slower

  Warming up --------------------------------------
     old default unary   220.776k i/100ms
     new default unary   305.148k i/100ms
  Calculating -------------------------------------
     old default unary      2.195M (± 1.3%) i/s -     11.039M in   5.030518s
     new default unary      3.081M (± 0.8%) i/s -     15.563M in   5.051871s

  Comparison:
     new default unary:  3080770.1 i/s
     old default unary:  2194765.4 i/s - 1.40x  (± 0.00) slower
  ```
2023-01-09 15:33:45 -06:00
fatkodima 83845c4d06 Fix schema cache dumping of virtual columns 2023-01-09 23:04:43 +02:00
Jonathan Hefner fad1c4c759 Use #except! in HashWithIndifferentAccess#except
This avoids multiple unnecessary allocations.

__Benchmark__

  ```ruby
  # frozen_string_literal: true
  require "benchmark/ips"
  require "active_support/all"

  class ActiveSupport::HashWithIndifferentAccess
    def old_except(*keys)
      slice(*self.keys - keys.map { |key| convert_key(key) })
    end

    def new_except(*keys)
      dup.except!(*keys)
    end
  end

  hwia = { foo: 1, bar: 2, baz: 3, qux: 4 }.with_indifferent_access
  splat_keys = [:bar, :baz]

  Benchmark.ips do |x|
    x.report("old except 1") do
      hwia.old_except(:bar)
    end

    x.report("new except 1") do
      hwia.new_except(:bar)
    end

    x.compare!
  end

  Benchmark.ips do |x|
    x.report("old except splat") do
      hwia.old_except(*splat_keys)
    end

    x.report("new except splat") do
      hwia.new_except(*splat_keys)
    end

    x.compare!
  end
  ```

__Results__

  ```
  Warming up --------------------------------------
          old except 1    18.079k i/100ms
          new except 1    28.205k i/100ms
  Calculating -------------------------------------
          old except 1    180.832k (± 1.7%) i/s -    903.950k in   5.000295s
          new except 1    282.729k (± 1.2%) i/s -      1.438M in   5.088540s

  Comparison:
          new except 1:   282729.2 i/s
          old except 1:   180831.5 i/s - 1.56x  (± 0.00) slower

  Warming up --------------------------------------
      old except splat    19.309k i/100ms
      new except splat    25.932k i/100ms
  Calculating -------------------------------------
      old except splat    194.091k (± 1.6%) i/s -    984.759k in   5.075044s
      new except splat    255.873k (± 1.3%) i/s -      1.297M in   5.068184s

  Comparison:
      new except splat:   255873.0 i/s
      old except splat:   194091.3 i/s - 1.32x  (± 0.00) slower
  ```
2023-01-09 14:28:15 -06:00
Aaron Patterson a4b098a12f
Merge pull request #46916 from ioquatix/actionpack-direct-set_response
Direct support for assigning to `self.response`.
2023-01-09 12:26:51 -08:00
Sam Ruby 9e6cb694dd
omit assets:precompile in Dockerfile for api only apps (#46938) 2023-01-09 20:23:05 +01:00
Alex Ghiculescu 16aaf7f62d
Run `test:prepare` before `bin/rails test` commands (#46664) 2023-01-09 20:22:27 +01:00
Eileen M. Uchitelle bf8e426cf8
Merge pull request #46931 from skipkayhil/fix-incompatible-sidekiq-test-2
Fix compatability between tests and Sidekiq 6.5
2023-01-09 11:43:33 -05:00
Sam Ruby ecc7491bc5
Change dockerfile from using Node 19 to match dev environment (#46794)
* Change dockerfile from using Node 19 to match dev environment

This is accomplished via installing volta: https://volta.sh/.

Also:
  * decouple the installation of libvips from node
  * add installation of the node_modules by running yarn

This pull request is part one of many intended to add features
from fly.io's generated Dockerfiles that are of general interest
to Rails.  For the overall plan, see:
https://community.fly.io/t/preparations-for-rails-7-1/9512

I'm making these changes in stages so that I can get early feedback
and in so doing improve future pull requests.

This changes was tested by generating an new application with esbuild
and deploying it.

attn: @ddh

* switch to double quotes to placate Rubocop

* add some Dockerfile tests

* generate a .node-version file if using_node?

* remove this for now

* reduce the number of layers

also adopt some of the style conventions already in use in the
Dockerfile with respect to quoting and spacing.

* add changelog entry
2023-01-09 17:34:58 +01:00
Petrik de Heus b8e09fc54e
Merge pull request #46927 from ghiculescu/missing-associated-guide-v2
[docs] Fix incorrect SQL in Active Record Querying guide
2023-01-09 07:11:45 +01:00
Hartley McGuire 285b63acd9
Fix compatability between tests and Sidekiq 6.5
Since Sidekiq 7.0 requires Ruby 2.7, older versions of Rails that
support older Rubies are still tested against Sidekiq 6.x.

Sidekiq::MAJOR was added in 7.0 so it can't be used for version testing,
see 862dc5b

The config change is due to changes in Sidekiq 6.5. These were accounted
for in 7a069dc but removed in 6d31993.
2023-01-08 20:41:59 -05:00
zzak ed65dfffc1 Add changelog for #46858 since it affects railties default middleware stack 2023-01-09 09:34:21 +09:00
Samuel Williams 28c8e2229f
Be more explicit when wrapping in an enumerable body. 2023-01-09 13:26:53 +13:00
Samuel Williams 36e2cb9abb
Test body proc detection. 2023-01-09 13:26:53 +13:00
Samuel Williams 5af76309ef
Close previous response if any. 2023-01-09 13:26:53 +13:00
Samuel Williams dc9c0859c0
Allow assigning streaming response body. 2023-01-09 13:26:53 +13:00
Samuel Williams 8e8695ea57
Fix comment. 2023-01-09 13:26:53 +13:00
Samuel Williams 6d5e0d2de2
Limit changes to new interface, `response=`. 2023-01-09 13:26:53 +13:00
Samuel Williams d8256ff62f
Fix test name. 2023-01-09 13:26:53 +13:00
Samuel Williams c239d6d79c
Spaces inside brackets. 2023-01-09 13:26:53 +13:00
Samuel Williams ec3830d54a
Add some tests. 2023-01-09 13:26:52 +13:00
Samuel Williams 49053fe8c0
Direct support for assigning to `self.response`. 2023-01-09 13:26:52 +13:00
zzak 145c96fc4e Fix link to association_basics.html guide 2023-01-09 08:23:04 +09:00
Jonathan Hefner aaf7bed003 Document ActionController::Rendering#render [ci-skip]
In #33418, documentation from `ActionView::Helpers::RenderingHelper#render`
was copied to `ActionController::Renderer#render` with the intention of
documenting `ActionController::Rendering#render`.  Since then, further
documentation has been added to `ActionController::Renderer#render`, and
`ActionController::Renderer#render` has been mistaken for
`ActionController::Rendering#render` (for example, in #46045).

This commit adds documentation to `ActionController::Rendering#render`
(which was previously `:nodoc:` because it is a simple override of
`AbstractController::Rendering#render`), and updates related
documentation to point to `ActionController::Rendering#render`.
2023-01-08 15:47:31 -06:00
Jonathan Hefner 6969cdc969 Revise ConditionalGet#expires_in doc [ci-skip] 2023-01-08 15:47:31 -06:00
Jonathan Hefner 2cb419f220 Clean up ConditionalGet#stale? doc [ci-skip] 2023-01-08 15:47:31 -06:00
Jonathan Hefner 657f214f25 Clean up ConditionalGet#fresh_when doc [ci-skip] 2023-01-08 15:47:31 -06:00
Jonathan Hefner 9a82d9585c Replace RFC 2616 links [ci-skip]
The w3.org RFC 2616 page displays an obtrusive "This document has been
superseded" overlay.  In regard to the `Cache-Control` header, RFC 2616
has been superseded by RFC 7234, which, in turn, has been superseded by
RFC 9111.

Therefore, this commit replaces links to RFC 2616 with links to either
MDN or RFC 9111.
2023-01-08 15:47:31 -06:00
Jonathan Hefner 70a67b9ddc Revise Rails::Application#encrypted doc [ci-skip] 2023-01-08 15:47:31 -06:00
Jonathan Hefner 8641197b54 Revise Rails::Application#credentials doc [ci-skip] 2023-01-08 15:47:31 -06:00
Jonathan Hefner 7208d524c8 Document EncryptedConfiguration#config [ci-skip] 2023-01-08 15:47:31 -06:00
Jonathan Hefner f46ce95c77 Document EncryptedConfiguration access methods [ci-skip] 2023-01-08 15:47:31 -06:00
Jonathan Hefner 17e29786b5 Document EncryptedConfiguration#read [ci-skip] 2023-01-08 15:47:31 -06:00
Jonathan Hefner 13f0ff9dfe Document increment order for {Date,etc}#advance [ci-skip] 2023-01-08 15:47:31 -06:00
Jonathan Hefner e0d384aeb4 Clarify caveats of parameterized association scope [ci-skip]
When joining or eager loading an association with a parameterized scope,
the scope block will not be called with a `nil` argument.  Rather,
`ActiveRecord::Reflection::AssociationReflection#check_eager_loadable!`
will raise an `ArgumentError`.

Closes #43539.

Co-authored-by: jcoleman <james.coleman@getbraintree.com>
2023-01-08 15:47:20 -06:00
Jonathan Hefner ce23110829 Coordinate FilterParameters and ParameterFilter docs [ci-skip]
This clarifies the `ActiveSupport::ParameterFilter` documentation, and
tweaks the example code to be more friendly to the syntax highlighter
(similar to the tweaks made for `ActionDispatch::Http::FilterParameters`
in 782bed5d45).

This also trims the `ActionDispatch::Http::FilterParameters`
documentation, and links it to `ActiveSupport::ParameterFilter`, since
`ActiveSupport::ParameterFilter` is responsible for filter behavior.
2023-01-08 15:47:20 -06:00
Jonathan Hefner a4528b58e9 Reference AS::Deprecation instance methods [ci-skip]
This is in line with transitioning away from the global
`ActiveSupport::Deprecation` instance, towards individual
`ActiveSupport::Deprecation` instances.
2023-01-08 15:47:20 -06:00
Jonathan Hefner 1aba8f64bf Document AD::Request::RFC* constants individually [ci-skip]
Prior to this commit, the list of RFCs and URLs was jumbled in a single
paragraph (with no delimiters) that was associated with the `RFC2616`
constant.

This commit splits up the list, associating each RFC with its respective
constant, and incorporating each URL into a link.
2023-01-08 15:47:20 -06:00
Jonathan Hefner cfe300ceb1 Format inline code [ci-skip] 2023-01-08 15:47:20 -06:00
Jonathan Hefner 3eadf057db Fix typos in API docs [ci-skip] 2023-01-08 15:47:20 -06:00
Jonathan Hefner 33557c5dca Indent private methods in code examples [ci-skip]
This matches the indentation used in generated code, such as code from
`railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb.tt`.
2023-01-08 15:47:20 -06:00
Jonathan Hefner 866be0b0f1 Clarify usage of data-turbo-confirm [ci-skip]
Follow-up to #46551.
2023-01-08 15:47:16 -06:00
Jonathan Hefner 61ecaa34ed Clarify instructions for testing new plugin [ci-skip]
Follow-up to #46014.
2023-01-08 15:47:11 -06:00