Skip to content

Commit

Permalink
Merge branch 'main' into assert-invalid
Browse files Browse the repository at this point in the history
  • Loading branch information
DanielaVelasquez authored Oct 12, 2024
2 parents 4360e5e + 184c962 commit 8180ca6
Show file tree
Hide file tree
Showing 154 changed files with 1,387 additions and 858 deletions.
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ gem "dartsass-rails"
gem "solid_cache"
gem "solid_queue"
gem "solid_cable"
gem "kamal", ">= 2.0.0.rc2", require: false
gem "kamal", ">= 2.1.0", require: false
gem "thruster", require: false
# require: false so bcrypt is loaded only when has_secure_password is used.
# This is to avoid Active Model (and by extension the entire framework)
Expand Down
6 changes: 3 additions & 3 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ GEM
railties (>= 6.0.0)
json (2.7.1)
jwt (2.7.1)
kamal (2.0.0.rc2)
kamal (2.1.0)
activesupport (>= 7.0)
base64 (~> 0.2)
bcrypt_pbkdf (~> 1.0)
Expand Down Expand Up @@ -641,7 +641,7 @@ GEM
websocket-extensions (0.1.5)
xpath (3.2.0)
nokogiri (~> 1.8)
zeitwerk (2.6.12)
zeitwerk (2.6.18)

PLATFORMS
ruby
Expand Down Expand Up @@ -671,7 +671,7 @@ DEPENDENCIES
jbuilder
jsbundling-rails
json (>= 2.0.0, != 2.7.0)
kamal (>= 2.0.0.rc2)
kamal (>= 2.1.0)
launchy
libxml-ruby
listen (~> 3.3)
Expand Down
2 changes: 1 addition & 1 deletion actioncable/test/channel/base_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ def error_handler
@connection.server.config.filter_parameters << :password
data = { password: "password", foo: "foo" }

assert_logged(':password=>"[FILTERED]"') do
assert_logged({ password: "[FILTERED]" }.inspect[1..-2]) do
@channel.perform_action data
end
end
Expand Down
19 changes: 19 additions & 0 deletions actionpack/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
* Update `ActionController::AllowBrowser` to support passing method names to `:block`

```ruby
class ApplicationController < ActionController::Base
allow_browser versions: :modern, block: :handle_outdated_browser

private
def handle_outdated_browser
render file: Rails.root.join("public/custom-error.html"), status: :not_acceptable
end
end
```

*Sean Doyle*

* Raise an `ArgumentError` when invalid `:only` or `:except` options are passed into `#resource` and `#resources`.

*Joshua Young*

## Rails 8.0.0.beta1 (September 26, 2024) ##

* Fix non-GET requests not updating cookies in `ActionController::TestCase`.
Expand Down
6 changes: 3 additions & 3 deletions actionpack/lib/action_controller/form_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ module ActionController
# default_form_builder AdminFormBuilder
# end
#
# Then in the view any form using `form_for` will be an instance of the
# specified form builder:
# Then in the view any form using `form_with` or `form_for` will be an
# instance of the specified form builder:
#
# <%= form_for(@instance) do |builder| %>
# <%= form_with(model: @instance) do |builder| %>
# <%= builder.special_field(:name) %>
# <% end %>
module FormBuilder
Expand Down
12 changes: 11 additions & 1 deletion actionpack/lib/action_controller/metal/allow_browser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,16 @@ module ClassMethods
# end
#
# class ApplicationController < ActionController::Base
# # Allow only browsers natively supporting webp images, web push, badges, import maps, CSS nesting, and CSS :has
# allow_browser versions: :modern, block: :handle_outdated_browser
#
# private
# def handle_outdated_browser
# render file: Rails.root.join("public/custom-error.html"), status: :not_acceptable
# end
# end
#
# class ApplicationController < ActionController::Base
# # All versions of Chrome and Opera will be allowed, but no versions of "internet explorer" (ie). Safari needs to be 16.4+ and Firefox 121+.
# allow_browser versions: { safari: 16.4, firefox: 121, ie: false }
# end
Expand All @@ -55,7 +65,7 @@ def allow_browser(versions:, block:)

if BrowserBlocker.new(request, versions: versions).blocked?
ActiveSupport::Notifications.instrument("browser_block.action_controller", request: request, versions: versions) do
instance_exec(&block)
block.is_a?(Symbol) ? send(block) : instance_exec(&block)
end
end
end
Expand Down
12 changes: 4 additions & 8 deletions actionpack/lib/action_dispatch/http/content_security_policy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@
module ActionDispatch # :nodoc:
# # Action Dispatch Content Security Policy
#
# Configures the HTTP [Content-Security-Policy]
# (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy)
# Configures the HTTP [Content-Security-Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy)
# response header to help protect against XSS and
# injection attacks.
#
Expand Down Expand Up @@ -227,8 +226,7 @@ def plugin_types(*types)
end
end

# Enable the [report-uri]
# (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/report-uri)
# Enable the [report-uri](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/report-uri)
# directive. Violation reports will be sent to the
# specified URI:
#
Expand All @@ -238,8 +236,7 @@ def report_uri(uri)
@directives["report-uri"] = [uri]
end

# Specify asset types for which [Subresource Integrity]
# (https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity) is required:
# Specify asset types for which [Subresource Integrity](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity) is required:
#
# policy.require_sri_for :script, :style
#
Expand All @@ -255,8 +252,7 @@ def require_sri_for(*types)
end
end

# Specify whether a [sandbox]
# (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/sandbox)
# Specify whether a [sandbox](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/sandbox)
# should be enabled for the requested resource:
#
# policy.sandbox
Expand Down
5 changes: 0 additions & 5 deletions actionpack/lib/action_dispatch/middleware/debug_view.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,12 @@ def initialize(assigns)
paths = RESCUES_TEMPLATE_PATHS.dup
lookup_context = ActionView::LookupContext.new(paths)
super(lookup_context, assigns, nil)
@exception_wrapper = assigns[:exception_wrapper]
end

def compiled_method_container
self.class
end

def error_highlight_available?
@exception_wrapper.error_highlight_available?
end

def debug_params(params)
clean_params = params.clone
clean_params.delete("action")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,12 +201,6 @@ def source_extracts
end
end

def error_highlight_available?
# ErrorHighlight.spot with backtrace_location keyword is available since
# error_highlight 0.4.0
defined?(ErrorHighlight) && Gem::Version.new(ErrorHighlight::VERSION) >= Gem::Version.new("0.4.0")
end

def trace_to_show
if traces["Application Trace"].empty? && rescue_template != "routing_error"
"Full Trace"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,6 @@
</tr>
</table>
</div>
<%- unless self.error_highlight_available? -%>
<p class="error_highlight_tip">Tip: You may want to add <code>gem "error_highlight", "&gt;= 0.4.0"</code> into your Gemfile, which will display the fine-grained error location.</p>
<%- end -%>
</div>
<% end %>
<% end %>
110 changes: 65 additions & 45 deletions actionpack/lib/action_dispatch/routing/mapper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -375,35 +375,18 @@ def dispatcher(raise_on_name_error)
Routing::RouteSet::Dispatcher.new raise_on_name_error
end

if Thread.respond_to?(:each_caller_location)
def route_source_location
if Mapper.route_source_locations
action_dispatch_dir = File.expand_path("..", __dir__)
Thread.each_caller_location do |location|
next if location.path.start_with?(action_dispatch_dir)
def route_source_location
if Mapper.route_source_locations
action_dispatch_dir = File.expand_path("..", __dir__)
Thread.each_caller_location do |location|
next if location.path.start_with?(action_dispatch_dir)

cleaned_path = Mapper.backtrace_cleaner.clean_frame(location.path)
next if cleaned_path.nil?
cleaned_path = Mapper.backtrace_cleaner.clean_frame(location.path)
next if cleaned_path.nil?

return "#{cleaned_path}:#{location.lineno}"
end
nil
end
end
else
def route_source_location
if Mapper.route_source_locations
action_dispatch_dir = File.expand_path("..", __dir__)
caller_locations.each do |location|
next if location.path.start_with?(action_dispatch_dir)

cleaned_path = Mapper.backtrace_cleaner.clean_frame(location.path)
next if cleaned_path.nil?

return "#{cleaned_path}:#{location.lineno}"
end
nil
return "#{cleaned_path}:#{location.lineno}"
end
nil
end
end
end
Expand Down Expand Up @@ -1179,13 +1162,28 @@ module Resources
CANONICAL_ACTIONS = %w(index create new show update destroy)

class Resource # :nodoc:
class << self
def default_actions(api_only)
if api_only
[:index, :create, :show, :update, :destroy]
else
[:index, :create, :new, :show, :update, :destroy, :edit]
end
end
end

attr_reader :controller, :path, :param

def initialize(entities, api_only, shallow, options = {})
if options[:param].to_s.include?(":")
raise ArgumentError, ":param option can't contain colons"
end

valid_actions = self.class.default_actions(false) # ignore api_only for this validation
if invalid_actions = invalid_only_except_options(options, valid_actions).presence
raise ArgumentError, ":only and :except must include only #{valid_actions}, but also included #{invalid_actions}"
end

@name = entities.to_s
@path = (options[:path] || @name).to_s
@controller = (options[:controller] || @name).to_s
Expand All @@ -1199,11 +1197,7 @@ def initialize(entities, api_only, shallow, options = {})
end

def default_actions
if @api_only
[:index, :create, :show, :update, :destroy]
else
[:index, :create, :new, :show, :update, :destroy, :edit]
end
self.class.default_actions(@api_only)
end

def actions
Expand Down Expand Up @@ -1271,9 +1265,24 @@ def shallow?
end

def singleton?; false; end

private
def invalid_only_except_options(options, valid_actions)
options.values_at(:only, :except).flatten.compact.uniq.map(&:to_sym) - valid_actions
end
end

class SingletonResource < Resource # :nodoc:
class << self
def default_actions(api_only)
if api_only
[:show, :create, :update, :destroy]
else
[:show, :create, :update, :destroy, :new, :edit]
end
end
end

def initialize(entities, api_only, shallow, options)
super
@as = nil
Expand All @@ -1282,11 +1291,7 @@ def initialize(entities, api_only, shallow, options)
end

def default_actions
if @api_only
[:show, :create, :update, :destroy]
else
[:show, :create, :update, :destroy, :new, :edit]
end
self.class.default_actions(@api_only)
end

def plural
Expand Down Expand Up @@ -1347,7 +1352,7 @@ def resource(*resources, &block)
end

with_scope_level(:resource) do
options = apply_action_options options
options = apply_action_options :resource, options
resource_scope(SingletonResource.new(resources.pop, api_only?, @scope[:shallow], options)) do
yield if block_given?

Expand Down Expand Up @@ -1517,7 +1522,7 @@ def resources(*resources, &block)
end

with_scope_level(:resources) do
options = apply_action_options options
options = apply_action_options :resources, options
resource_scope(Resource.new(resources.pop, api_only?, @scope[:shallow], options)) do
yield if block_given?

Expand Down Expand Up @@ -1786,17 +1791,32 @@ def apply_common_behavior_for(method, resources, options, &block)
false
end

def apply_action_options(options)
def apply_action_options(method, options)
return options if action_options? options
options.merge scope_action_options
options.merge scope_action_options(method)
end

def action_options?(options)
options[:only] || options[:except]
end

def scope_action_options
@scope[:action_options] || {}
def scope_action_options(method)
return {} unless @scope[:action_options]

actions = applicable_actions_for(method)
@scope[:action_options].dup.tap do |options|
(options[:only] = Array(options[:only]) & actions) if options[:only]
(options[:except] = Array(options[:except]) & actions) if options[:except]
end
end

def applicable_actions_for(method)
case method
when :resource
SingletonResource.default_actions(api_only?)
when :resources
Resource.default_actions(api_only?)
end
end

def resource_scope?
Expand Down Expand Up @@ -2209,8 +2229,8 @@ def direct(name, options = {}, &block)
end

# Define custom polymorphic mappings of models to URLs. This alters the behavior
# of `polymorphic_url` and consequently the behavior of `link_to` and `form_for`
# when passed a model instance, e.g:
# of `polymorphic_url` and consequently the behavior of `link_to`, `form_with`
# and `form_for` when passed a model instance, e.g:
#
# resource :basket
#
Expand All @@ -2219,7 +2239,7 @@ def direct(name, options = {}, &block)
# end
#
# This will now generate "/basket" when a `Basket` instance is passed to
# `link_to` or `form_for` instead of the standard "/baskets/:id".
# `link_to`, `form_with` or `form_for` instead of the standard "/baskets/:id".
#
# NOTE: This custom behavior only applies to simple polymorphic URLs where a
# single model instance is passed and not more complicated forms, e.g:
Expand Down
Loading

0 comments on commit 8180ca6

Please sign in to comment.