Skip to content

Where with block #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 36 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
dc778f8
Only use valid handlers in resolver_shared_tests
jhawthorn Feb 17, 2020
8762d93
Add tests of resolver variant handling
jhawthorn Feb 17, 2020
e53c45b
Introduce Resolver::PathParser
jhawthorn Oct 1, 2019
827119c
Mark PathParser as :nodoc:
jhawthorn May 20, 2020
f02ab3e
Add status the 103 Early Hints as Not content for action_dispatch
roramirez May 20, 2020
096d143
Clear cache after setting Template::Types delegate
jhawthorn May 21, 2020
86a9b36
Remove unused `limit` on `enum` and `set` columns in MySQL
kamipo May 24, 2020
e5953db
`merge(..., rewhere: true)` should have the ability to overwrite non-…
kamipo May 24, 2020
8e7080e
Merge pull request #39408 from kamipo/remove_limit_on_enum
kamipo May 25, 2020
0571da9
Merge pull request #39415 from kamipo/merge_rewhere_with_non_attrs
kamipo May 25, 2020
2a1ec6e
Fix typo
swaggermeister May 25, 2020
4f95ff7
Fix preloading for polymorphic association with custom scope
kamipo May 25, 2020
f7d21e4
Merge pull request #39423 from swaggermeister/patch-1
eugeneius May 25, 2020
803c030
Merge pull request #39424 from kamipo/fix_preload_for_polymorphic_ass…
kamipo May 25, 2020
d02d259
Fix Active Storage behavior on record dup
jonathanhefner May 26, 2020
a47e0c1
Merge pull request #39417 from roramirez/early-hints-no-content
eugeneius May 26, 2020
2db687f
Remove dup from Request#set_cotent_type
vinistock May 26, 2020
3582de9
Refactor `remove_columns` inverting to return a flat invert command
kamipo May 26, 2020
8153954
Merge pull request #39437 from vinistock/remove_dup_from_set_content_…
kamipo May 26, 2020
64b17ba
Remove dup from post body for forcing encoding (#39438)
vinistock May 26, 2020
c4682ea
Fix "warning: instance variable @klass not initialized"
kamipo May 26, 2020
7c93699
Prefer string interpolation over direct mutation
kamipo May 26, 2020
da21ac7
No need to extend ActionController::Caching by ActiveSupport::Autoload
fatkodima May 26, 2020
8071ba7
A few action_controller docs corrections
fatkodima May 25, 2020
a970efb
Merge pull request #39442 from fatkodima/actionpack-docs-fixes
vipulnsward May 26, 2020
b91906c
Merge pull request #39441 from fatkodima/caching-delete-autoload
kamipo May 26, 2020
4671fe2
Ensure cache fragment digests include all templates
alipman88 Apr 24, 2020
dd7a673
Remove redundant @virtual_path variable
alipman88 Apr 26, 2020
b378bda
Merge pull request #39060 from alipman88/fix_cache_fragment_digests
tenderlove May 26, 2020
95e1305
Fix flaky assert queries tests
kamipo May 26, 2020
787b991
`rewhere` allow to overwrite non-attribute nodes
kamipo May 27, 2020
a70ad60
Add railties test of custom handlers and formats
jhawthorn May 27, 2020
db543ba
Merge pull request #39361 from jhawthorn/path_parser
jhawthorn May 27, 2020
aaf1473
Allow calling where with a block
May 27, 2020
bf0f502
Allow getting attributes through method calls on composer
May 27, 2020
189b077
Allow calling methods as instance methods on blocks
May 26, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions actionmailer/lib/action_mailer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,5 @@ def self.eager_load!
ActiveSupport.on_load(:action_view) do
ActionView::Base.default_formats ||= Mime::SET.symbols
ActionView::Template::Types.delegate_to Mime
ActionView::LookupContext::DetailsKey.clear
end
1 change: 0 additions & 1 deletion actionpack/lib/action_controller/caching.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ module ActionController
# config.action_controller.cache_store = :mem_cache_store, Memcached::Rails.new('localhost:11211')
# config.action_controller.cache_store = MyOwnStore.new('parameter')
module Caching
extend ActiveSupport::Autoload
extend ActiveSupport::Concern

included do
Expand Down
2 changes: 1 addition & 1 deletion actionpack/lib/action_controller/metal/implicit_render.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ module ActionController
# Third, if we DON'T find a template AND the request is a page load in a web
# browser (technically, a non-XHR GET request for an HTML response) where
# you reasonably expect to have rendered a template, then we raise
# <tt>ActionView::UnknownFormat</tt> with an explanation.
# <tt>ActionController::MissingExactTemplate</tt> with an explanation.
#
# Finally, if we DON'T find a template AND the request isn't a browser page
# load, then we implicitly respond with <tt>204 No Content</tt>.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ class Parameters
# to change these is to specify `always_permitted_parameters` in your
# config. For instance:
#
# config.always_permitted_parameters = %w( controller action format )
# config.action_controller.always_permitted_parameters = %w( controller action format )
cattr_accessor :always_permitted_parameters, default: %w( controller action )

class << self
Expand Down
1 change: 1 addition & 0 deletions actionpack/lib/action_dispatch.rb
Original file line number Diff line number Diff line change
Expand Up @@ -116,4 +116,5 @@ module Session
ActiveSupport.on_load(:action_view) do
ActionView::Base.default_formats ||= Mime::SET.symbols
ActionView::Template::Types.delegate_to Mime
ActionView::LookupContext::DetailsKey.clear
end
2 changes: 1 addition & 1 deletion actionpack/lib/action_dispatch/http/request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ def raw_post
# variable is already set, wrap it in a StringIO.
def body
if raw_post = get_header("RAW_POST_DATA")
raw_post = raw_post.dup.force_encoding(Encoding::BINARY)
raw_post = (+raw_post).force_encoding(Encoding::BINARY)
StringIO.new(raw_post)
else
body_stream
Expand Down
6 changes: 3 additions & 3 deletions actionpack/lib/action_dispatch/http/response.rb
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def each(&block)
CONTENT_TYPE = "Content-Type"
SET_COOKIE = "Set-Cookie"
LOCATION = "Location"
NO_CONTENT_CODES = [100, 101, 102, 204, 205, 304]
NO_CONTENT_CODES = [100, 101, 102, 103, 204, 205, 304]

cattr_accessor :default_charset, default: "utf-8"
cattr_accessor :default_headers
Expand Down Expand Up @@ -448,8 +448,8 @@ def parsed_content_type_header
end

def set_content_type(content_type, charset)
type = (content_type || "").dup
type << "; charset=#{charset.to_s.downcase}" if charset
type = content_type || ""
type = "#{type}; charset=#{charset.to_s.downcase}" if charset
set_header CONTENT_TYPE, type
end

Expand Down
11 changes: 11 additions & 0 deletions actionpack/test/controller/new_base/bare_metal_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ def processing
head 102
end

def early_hints
self.content_type = "text/html"
head 103
end

def no_content
self.content_type = "text/html"
head 204
Expand Down Expand Up @@ -121,6 +126,12 @@ class HeadTest < ActiveSupport::TestCase
assert_nil headers["Content-Length"]
end

test "head :early_hints (103) does not return a content-type header" do
headers = HeadController.action(:early_hints).call(Rack::MockRequest.env_for("/")).second
assert_nil headers["Content-Type"]
assert_nil headers["Content-Length"]
end

test "head :no_content (204) does not return a content-type header" do
headers = HeadController.action(:no_content).call(Rack::MockRequest.env_for("/")).second
assert_nil headers["Content-Type"]
Expand Down
4 changes: 2 additions & 2 deletions actionpack/test/dispatch/response_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ def test_only_set_charset_still_defaults_to_text_html
end

test "content length" do
[100, 101, 102, 204].each do |c|
[100, 101, 102, 103, 204].each do |c|
@response = ActionDispatch::Response.new
@response.status = c.to_s
@response.set_header "Content-Length", "0"
Expand All @@ -163,7 +163,7 @@ def test_only_set_charset_still_defaults_to_text_html
end

test "does not contain a message-body" do
[100, 101, 102, 204, 304].each do |c|
[100, 101, 102, 103, 204, 304].each do |c|
@response = ActionDispatch::Response.new
@response.status = c.to_s
@response.body = "Body must not be included"
Expand Down
9 changes: 9 additions & 0 deletions actionview/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
* Ensure cache fragment digests include all relevant template dependencies when
fragments are contained in a block passed to the render helper. Remove the
virtual_path keyword arguments found in CacheHelper as they no longer possess
any function following 1581cab.

Fixes #38984

*Aaron Lipman*

* Deprecate `config.action_view.raise_on_missing_translations` in favor of
`config.i18n.raise_on_missing_translations`.

Expand Down
8 changes: 4 additions & 4 deletions actionview/lib/action_view/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -269,13 +269,13 @@ def initialize(lookup_context = nil, assigns = {}, controller = nil, formats = N
_prepare_context
end

def _run(method, template, locals, buffer, &block)
_old_output_buffer, _old_virtual_path, _old_template = @output_buffer, @virtual_path, @current_template
@current_template = template
def _run(method, template, locals, buffer, add_to_stack: true, &block)
_old_output_buffer, _old_template = @output_buffer, @current_template
@current_template = template if add_to_stack
@output_buffer = buffer
send(method, locals, buffer, &block)
ensure
@output_buffer, @virtual_path, @current_template = _old_output_buffer, _old_virtual_path, _old_template
@output_buffer, @current_template = _old_output_buffer, _old_template
end

def compiled_method_container
Expand Down
1 change: 0 additions & 1 deletion actionview/lib/action_view/context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ module Context
def _prepare_context
@view_flow = OutputFlow.new
@output_buffer = nil
@virtual_path = nil
end

# Encapsulates the interaction with the view flow so it
Expand Down
22 changes: 8 additions & 14 deletions actionview/lib/action_view/helpers/cache_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ module CacheHelper
# expire the cache.
def cache(name = {}, options = {}, &block)
if controller.respond_to?(:perform_caching) && controller.perform_caching
name_options = options.slice(:skip_digest, :virtual_path)
name_options = options.slice(:skip_digest)
safe_concat(fragment_for(cache_fragment_name(name, **name_options), options, &block))
else
yield
Expand Down Expand Up @@ -205,14 +205,11 @@ def cache_unless(condition, name = {}, options = {}, &block)
# fragments can be manually bypassed. This is useful when cache fragments
# cannot be manually expired unless you know the exact key which is the
# case when using memcached.
#
# The digest will be generated using +virtual_path:+ if it is provided.
#
def cache_fragment_name(name = {}, skip_digest: nil, virtual_path: nil, digest_path: nil)
def cache_fragment_name(name = {}, skip_digest: nil, digest_path: nil)
if skip_digest
name
else
fragment_name_with_digest(name, virtual_path, digest_path)
fragment_name_with_digest(name, digest_path)
end
end

Expand All @@ -227,14 +224,11 @@ def digest_path_from_template(template) # :nodoc:
end

private
def fragment_name_with_digest(name, virtual_path, digest_path)
virtual_path ||= @virtual_path

if virtual_path || digest_path
name = controller.url_for(name).split("://").last if name.is_a?(Hash)
def fragment_name_with_digest(name, digest_path)
name = controller.url_for(name).split("://").last if name.is_a?(Hash)

if @current_template&.virtual_path || digest_path
digest_path ||= digest_path_from_template(@current_template)

[ digest_path, name ]
else
name
Expand All @@ -243,10 +237,10 @@ def fragment_name_with_digest(name, virtual_path, digest_path)

def fragment_for(name = {}, options = nil, &block)
if content = read_fragment_for(name, options)
@view_renderer.cache_hits[@virtual_path] = :hit if defined?(@view_renderer)
@view_renderer.cache_hits[@current_template&.virtual_path] = :hit if defined?(@view_renderer)
content
else
@view_renderer.cache_hits[@virtual_path] = :miss if defined?(@view_renderer)
@view_renderer.cache_hits[@current_template&.virtual_path] = :miss if defined?(@view_renderer)
write_fragment_for(name, options, &block)
end
end
Expand Down
2 changes: 1 addition & 1 deletion actionview/lib/action_view/helpers/form_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1793,7 +1793,7 @@ def initialize(object_name, object, template, options)
# Wraps ActionView::Helpers::FormHelper#time_field for form builders:
#
# <%= form_with model: @user do |f| %>
# <%= f.time_field :borned_at %>
# <%= f.time_field :born_at %>
# <% end %>
#
# Please refer to the documentation of the base helper for details.
Expand Down
6 changes: 3 additions & 3 deletions actionview/lib/action_view/helpers/translation_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,10 @@ def localize(object, **options)
def scope_key_by_partial(key)
stringified_key = key.to_s
if stringified_key.start_with?(".")
if @virtual_path
if @current_template&.virtual_path
@_scope_key_by_partial_cache ||= {}
@_scope_key_by_partial_cache[@virtual_path] ||= @virtual_path.gsub(%r{/_?}, ".")
"#{@_scope_key_by_partial_cache[@virtual_path]}#{stringified_key}"
@_scope_key_by_partial_cache[@current_template.virtual_path] ||= @current_template.virtual_path.gsub(%r{/_?}, ".")
"#{@_scope_key_by_partial_cache[@current_template.virtual_path]}#{stringified_key}"
else
raise "Cannot use t(#{key.inspect}) shortcut because path is not available"
end
Expand Down
2 changes: 1 addition & 1 deletion actionview/lib/action_view/renderer/partial_renderer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ def render_partial_template(view, locals, template, layout, block)
identifier: template.identifier,
layout: layout && layout.virtual_path
) do |payload|
content = template.render(view, locals) do |*name|
content = template.render(view, locals, add_to_stack: !block) do |*name|
view._layout_for(*name, &block)
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def collection_by_cache_keys(view, template, collection)
end

def expanded_cache_key(key, view, template, digest_path)
key = view.combined_fragment_cache_key(view.cache_fragment_name(key, virtual_path: template.virtual_path, digest_path: digest_path))
key = view.combined_fragment_cache_key(view.cache_fragment_name(key, digest_path: digest_path))
key.frozen? ? key.dup : key # #read_multi & #write may require mutability, Dalli 2.6.0.
end

Expand Down
4 changes: 2 additions & 2 deletions actionview/lib/action_view/template.rb
Original file line number Diff line number Diff line change
Expand Up @@ -176,10 +176,10 @@ def supports_streaming?
# This method is instrumented as "!render_template.action_view". Notice that
# we use a bang in this instrumentation because you don't want to
# consume this in production. This is only slow if it's being listened to.
def render(view, locals, buffer = ActionView::OutputBuffer.new, &block)
def render(view, locals, buffer = ActionView::OutputBuffer.new, add_to_stack: true, &block)
instrument_render_template do
compile!(view)
view._run(method_name, self, locals, buffer, &block)
view._run(method_name, self, locals, buffer, add_to_stack: add_to_stack, &block)
end
rescue => e
handle_render_error(view, e)
Expand Down
55 changes: 44 additions & 11 deletions actionview/lib/action_view/template/resolver.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,44 @@ def to_str
alias :to_s :to_str
end

class PathParser # :nodoc:
def initialize
@regex = build_path_regex
end

def build_path_regex
handlers = Template::Handlers.extensions.map { |x| Regexp.escape(x) }.join("|")
formats = Template::Types.symbols.map { |x| Regexp.escape(x) }.join("|")
locales = "[a-z]{2}(?:-[A-Z]{2})?"
variants = "[^.]*"

%r{
\A
(?:(?<prefix>.*)/)?
(?<partial>_)?
(?<action>.*?)
(?:\.(?<locale>#{locales}))??
(?:\.(?<format>#{formats}))??
(?:\+(?<variant>#{variants}))??
(?:\.(?<handler>#{handlers}))?
\z
}x
end

def parse(path)
match = @regex.match(path)
{
prefix: match[:prefix] || "",
action: match[:action],
partial: !!match[:partial],
locale: match[:locale]&.to_sym,
handler: match[:handler]&.to_sym,
format: match[:format]&.to_sym,
variant: match[:variant]
}
end
end

# Threadsafe template cache
class Cache #:nodoc:
class SmallCache < Concurrent::Map
Expand Down Expand Up @@ -172,11 +210,13 @@ def initialize(pattern = nil)
@pattern = DEFAULT_PATTERN
end
@unbound_templates = Concurrent::Map.new
@path_parser = PathParser.new
super()
end

def clear_cache
@unbound_templates.clear
@path_parser = PathParser.new
super()
end

Expand Down Expand Up @@ -278,18 +318,11 @@ def escape_entry(entry)
# from the path, or the handler, we should return the array of formats given
# to the resolver.
def extract_handler_and_format_and_variant(path)
pieces = File.basename(path).split(".")
pieces.shift
details = @path_parser.parse(path)

extension = pieces.pop

handler = Template.handler_for_extension(extension)
format, variant = pieces.last.split(EXTENSIONS[:variants], 2) if pieces.last
format = if format
Template::Types[format]&.ref
elsif handler.respond_to?(:default_format) # default_format can return nil
handler.default_format
end
handler = Template.handler_for_extension(details[:handler])
format = details[:format] || handler.try(:default_format)
variant = details[:variant]

# Template::Types[format] and handler.default_format can return nil
[handler, format, variant]
Expand Down
2 changes: 0 additions & 2 deletions actionview/test/abstract_unit.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,6 @@ def view
end

def render_erb(string)
@virtual_path = nil

template = ActionView::Template.new(
string.strip,
"test template",
Expand Down
4 changes: 4 additions & 0 deletions actionview/test/actionpack/controller/layout_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,13 @@ def self._implied_layout_name; to_s.underscore.gsub(/_controller$/, "") ; end
module TemplateHandlerHelper
def with_template_handler(*extensions, handler)
ActionView::Template.register_template_handler(*extensions, handler)
ActionController::Base.view_paths.paths.each(&:clear_cache)
ActionView::LookupContext::DetailsKey.clear
yield
ensure
ActionView::Template.unregister_template_handler(*extensions)
ActionController::Base.view_paths.paths.each(&:clear_cache)
ActionView::LookupContext::DetailsKey.clear
end
end

Expand Down
1 change: 0 additions & 1 deletion actionview/test/activerecord/relation_cache_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ def setup
view_paths = ActionController::Base.view_paths
lookup_context = ActionView::LookupContext.new(view_paths, {}, ["test"])
@view_renderer = ActionView::Renderer.new(lookup_context)
@virtual_path = "path"
@current_template = lookup_context.find "test/hello_world"

controller.cache_store = ActiveSupport::Cache::MemoryStore.new
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<%= render layout: "layouts/yield_only" do %><%= cache "foo" do %>CAT<% end %><% end %>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<%= render layout: "layouts/yield_only" do %><%= cache "foo" do %>DOG<% end %><% end %>
Loading