Skip to content

Commit

Permalink
Merge branch 'main' into params-mandate
Browse files Browse the repository at this point in the history
  • Loading branch information
dhh authored Sep 7, 2024
2 parents 4fc0c3e + 1f64e4d commit 47be670
Show file tree
Hide file tree
Showing 77 changed files with 914 additions and 618 deletions.
2 changes: 1 addition & 1 deletion .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.191.1/containers/ruby/.devcontainer/base.Dockerfile

# [Choice] Ruby version: 3, 3.3, 3.2, 3.1, 3.0, 2, 2.7, 2.6
ARG VARIANT="3.3.4"
ARG VARIANT="3.3.5"
FROM ghcr.io/rails/devcontainer/images/ruby:${VARIANT}

# [Optional] Uncomment this section to install additional OS packages.
Expand Down
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ gem "cssbundling-rails"
gem "importmap-rails", ">= 1.2.3"
gem "tailwindcss-rails"
gem "dartsass-rails"
gem "solid_cache"
gem "solid_queue"
gem "kamal", require: false
gem "thruster", require: false
# require: false so bcrypt is loaded only when has_secure_password is used.
Expand Down
21 changes: 17 additions & 4 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ GEM
drb (2.2.1)
ed25519 (1.3.0)
erubi (1.13.0)
et-orbi (1.2.7)
et-orbi (1.2.11)
tzinfo
event_emitter (0.2.6)
execjs (2.9.1)
Expand Down Expand Up @@ -244,8 +244,8 @@ GEM
ffi (1.17.0)
ffi (1.17.0-x86_64-darwin)
ffi (1.17.0-x86_64-linux-gnu)
fugit (1.9.0)
et-orbi (~> 1, >= 1.2.7)
fugit (1.11.1)
et-orbi (~> 1, >= 1.2.11)
raabro (~> 1.4)
globalid (1.2.1)
activesupport (>= 6.1)
Expand Down Expand Up @@ -545,6 +545,17 @@ GEM
rake
serverengine (~> 2.0.5)
thor
solid_cache (1.0.4)
activejob (>= 7.2)
activerecord (>= 7.2)
railties (>= 7.2)
solid_queue (0.8.1)
activejob (>= 7.1)
activerecord (>= 7.1)
concurrent-ruby (>= 1.3.1)
fugit (~> 1.11.0)
railties (>= 7.1)
thor (~> 1.3.1)
sorted_set (1.0.3)
rbtree
set (~> 1.0)
Expand Down Expand Up @@ -581,7 +592,7 @@ GEM
railties (>= 6.0.0)
terser (1.1.20)
execjs (>= 0.3.0, < 3)
thor (1.3.0)
thor (1.3.2)
thruster (0.1.7)
thruster (0.1.7-x86_64-darwin)
thruster (0.1.7-x86_64-linux)
Expand Down Expand Up @@ -691,6 +702,8 @@ DEPENDENCIES
selenium-webdriver (>= 4.20.0)
sidekiq
sneakers
solid_cache
solid_queue
sprockets-rails (>= 2.0.0)
sqlite3 (>= 2.0)
stackprof
Expand Down
2 changes: 1 addition & 1 deletion actionmailer/test/callbacks_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class ActionMailerCallbacksTest < ActiveSupport::TestCase
end

test "deliver_now! should call after_deliver callback" do
CallbackMailer.test_message.deliver_now
CallbackMailer.test_message.deliver_now!

assert_kind_of CallbackMailer, CallbackMailer.after_deliver_instance
end
Expand Down
8 changes: 6 additions & 2 deletions actionpack/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
* Introduce safer, more explicit params handling method.
- `params.expect(table: [ :attr ])` replaces `params.require(:table).permit(:attr)`
* Introduce safer, more explicit params handling method with `params#expect` such that
`params.expect(table: [ :attr ])` replaces `params.require(:table).permit(:attr)`

Ensures params are filtered with consideration for the expected
types of values, improving handling of params and avoiding ignorable
Expand Down Expand Up @@ -45,6 +45,10 @@

*Martin Emde*

* System Testing: Disable Chrome's search engine choice by default in system tests.
*glaszig*
* Fix `Request#raw_post` raising `NoMethodError` when `rack.input` is `nil`.
*Hartley McGuire*
Expand Down
1 change: 1 addition & 0 deletions actionpack/lib/action_controller/api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ def self.without_modules(*modules)
BasicImplicitRender,
StrongParameters,
RateLimiting,
Caching,

DataStreaming,
DefaultHeaders,
Expand Down
33 changes: 12 additions & 21 deletions actionpack/lib/action_dispatch/system_testing/browser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ class Browser # :nodoc:

def initialize(name)
@name = name
set_default_options
end

def type
Expand All @@ -27,9 +26,9 @@ def options
@options ||=
case type
when :chrome
::Selenium::WebDriver::Chrome::Options.new
default_chrome_options
when :firefox
::Selenium::WebDriver::Firefox::Options.new
default_firefox_options
end
end

Expand All @@ -49,26 +48,18 @@ def preload
end

private
def set_default_options
case name
when :headless_chrome
set_headless_chrome_browser_options
when :headless_firefox
set_headless_firefox_browser_options
end
def default_chrome_options
options = ::Selenium::WebDriver::Chrome::Options.new
options.add_argument("--disable-search-engine-choice-screen")
options.add_argument("--headless") if name == :headless_chrome
options.add_argument("--disable-gpu") if Gem.win_platform?
options
end

def set_headless_chrome_browser_options
configure do |capabilities|
capabilities.add_argument("--headless")
capabilities.add_argument("--disable-gpu") if Gem.win_platform?
end
end

def set_headless_firefox_browser_options
configure do |capabilities|
capabilities.add_argument("-headless")
end
def default_firefox_options
options = ::Selenium::WebDriver::Firefox::Options.new
options.add_argument("-headless") if name == :headless_firefox
options
end

def resolve_driver_path(namespace)
Expand Down
40 changes: 40 additions & 0 deletions actionpack/test/controller/api/rate_limiting_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# frozen_string_literal: true

require "abstract_unit"

class ApiRateLimitedController < ActionController::API
self.cache_store = ActiveSupport::Cache::MemoryStore.new
rate_limit to: 2, within: 2.seconds, only: :limited_to_two

def limited_to_two
head :ok
end
end

class ApiRateLimitingTest < ActionController::TestCase
tests ApiRateLimitedController

setup do
ApiRateLimitedController.cache_store.clear
end

test "exceeding basic limit" do
get :limited_to_two
get :limited_to_two
assert_response :ok

get :limited_to_two
assert_response :too_many_requests
end

test "limit resets after time" do
get :limited_to_two
get :limited_to_two
assert_response :ok

travel_to Time.now + 3.seconds do
get :limited_to_two
assert_response :ok
end
end
end
4 changes: 2 additions & 2 deletions actionpack/test/dispatch/system_testing/driver_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ class DriverTest < ActiveSupport::TestCase

expected = {
"goog:chromeOptions" => {
"args" => ["start-maximized"],
"args" => ["--disable-search-engine-choice-screen", "start-maximized"],
"mobileEmulation" => { "deviceName" => "iphone 6" },
"prefs" => { "detach" => true }
},
Expand All @@ -101,7 +101,7 @@ class DriverTest < ActiveSupport::TestCase

expected = {
"goog:chromeOptions" => {
"args" => ["--headless", "start-maximized"],
"args" => ["--disable-search-engine-choice-screen", "--headless", "start-maximized"],
"mobileEmulation" => { "deviceName" => "iphone 6" },
"prefs" => { "detach" => true }
},
Expand Down
4 changes: 2 additions & 2 deletions actionview/lib/action_view/helpers/form_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2020,8 +2020,8 @@ def field_name(method, *methods, multiple: false, index: @options[:index])
#
# Please refer to the documentation of the base helper for details.

(field_helpers - [:label, :checkbox, :radio_button, :fields_for, :fields, :hidden_field, :file_field]).each do |selector|
ActiveSupport::CodeGenerator.batch(self, __FILE__, __LINE__) do |code_generator|
ActiveSupport::CodeGenerator.batch(self, __FILE__, __LINE__) do |code_generator|
(field_helpers - [:label, :checkbox, :radio_button, :fields_for, :fields, :hidden_field, :file_field]).each do |selector|
code_generator.class_eval do |batch|
batch <<
"def #{selector}(method, options = {})" <<
Expand Down
27 changes: 27 additions & 0 deletions activerecord/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,30 @@
* Deprecate `unsigned_float` and `unsigned_decimal` short-hand column methods.

As of MySQL 8.0.17, the UNSIGNED attribute is deprecated for columns of type FLOAT, DOUBLE,
and DECIMAL. Consider using a simple CHECK constraint instead for such columns.

https://dev.mysql.com/doc/refman/8.0/en/numeric-type-syntax.html

*Ryuta Kamizono*

* Drop MySQL 5.5 support.

MySQL 5.5 is the only version that does not support datetime with precision,
which we have supported in the core. Now we support MySQL 5.6.4 or later, which
is the first version to support datetime with precision.

*Ryuta Kamizono*

* Make Active Record asynchronous queries compatible with transactional fixtures.

Previously transactional fixtures would disable asynchronous queries, because transactional
fixtures impose all queries use the same connection.

Now asynchronous queries will use the connection pinned by transactional fixtures, and behave
much closer to production.

*Jean Boussier*

* Deserialize binary data before decrypting

This ensures that we call `PG::Connection.unescape_bytea` on PostgreSQL before decryption.
Expand Down
30 changes: 25 additions & 5 deletions activerecord/lib/active_record/associations/association.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ module Associations
# the <tt>reflection</tt> object represents a <tt>:has_many</tt> macro.
class Association # :nodoc:
attr_accessor :owner
attr_reader :target, :reflection, :disable_joins
attr_reader :reflection, :disable_joins

delegate :options, to: :reflection

Expand All @@ -50,6 +50,13 @@ def initialize(owner, reflection)
@skip_strict_loading = nil
end

def target
if @target.is_a?(Promise)
@target = @target.value
end
@target
end

# Resets the \loaded flag to +false+ and sets the \target to +nil+.
def reset
@loaded = false
Expand Down Expand Up @@ -172,14 +179,21 @@ def extensions
# ActiveRecord::RecordNotFound is rescued within the method, and it is
# not reraised. The proxy is \reset and +nil+ is the return value.
def load_target
@target = find_target if (@stale_state && stale_target?) || find_target?
@target = find_target(async: false) if (@stale_state && stale_target?) || find_target?

loaded! unless loaded?
target
rescue ActiveRecord::RecordNotFound
reset
end

def async_load_target # :nodoc:
@target = find_target(async: true) if (@stale_state && stale_target?) || find_target?

loaded! unless loaded?
nil
end

# We can't dump @reflection and @through_reflection since it contains the scope proc
def marshal_dump
ivars = (instance_variables - [:@reflection, :@through_reflection]).map { |name| [name, instance_variable_get(name)] }
Expand Down Expand Up @@ -223,13 +237,19 @@ def ensure_klass_exists!
klass
end

def find_target
def find_target(async: false)
if violates_strict_loading?
Base.strict_loading_violation!(owner: owner.class, reflection: reflection)
end

scope = self.scope
return scope.to_a if skip_statement_cache?(scope)
if skip_statement_cache?(scope)
if async
return scope.load_async.then(&:to_a)
else
return scope.to_a
end
end

sc = reflection.association_scope_cache(klass, owner) do |params|
as = AssociationScope.create { params.bind }
Expand All @@ -238,7 +258,7 @@ def find_target

binds = AssociationScope.get_bind_values(owner, reflection.chain)
klass.with_connection do |c|
sc.execute(binds, c) do |record|
sc.execute(binds, c, async: async) do |record|
set_inverse_instance(record)
if owner.strict_loading_n_plus_one_only? && reflection.macro == :has_many
record.strict_loading!
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,8 @@ def delete_through_records(records)
end
end

def find_target
def find_target(async: false)
raise NotImplementedError, "No async loading for HasManyThroughAssociation yet" if async
return [] unless target_reflection_has_associated_record?
return scope.to_a if disable_joins
super
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ def reader
def reset
super
@target = nil
@future_target = nil
end

# Implements the writer method, e.g. foo.bar= for Foo.belongs_to :bar
Expand All @@ -43,11 +44,15 @@ def scope_for_create
super.except!(*Array(klass.primary_key))
end

def find_target
def find_target(async: false)
if disable_joins
scope.first
if async
scope.load_async.then(&:first)
else
scope.first
end
else
super.first
super.then(&:first)
end
end

Expand Down
Loading

0 comments on commit 47be670

Please sign in to comment.