-
Notifications
You must be signed in to change notification settings - Fork 21.7k
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
Action View: Remove internal calls to tag
with positional arguments
#49377
base: main
Are you sure you want to change the base?
Action View: Remove internal calls to tag
with positional arguments
#49377
Conversation
6cd9799
to
c15cde8
Compare
How much slower are the new calls? |
@@ -1007,8 +1010,8 @@ def extra_tags_for_form(html_options) | |||
|
|||
def form_tag_html(html_options) | |||
extra_tags = extra_tags_for_form(html_options) | |||
html = tag(:form, html_options, true) + extra_tags | |||
prevent_content_exfiltration(html) | |||
html = content_tag(:form, extra_tags, html_options).then { |html| html.delete_suffix!("</form>") } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Building a tag, just to remove the closing tag, and then calling html_safe
doesn't seem worthy doing. You are making the framework do more work than it is necessary. This has performance impact.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change would be unnecessary if #44275 were merged.
Simple benchmark shows me it is almost 2 slower
I don't think it is worthy changing internal usage. |
@rafaelfranca thank you so much for your detailed review, especially the benchmark. I would love to address these performance issues enough to make my recent batch of TagBuilder pull requests more viable. I've opened #49390 to explore what it'd be like to dynamically define methods to avoid calls to |
c15cde8
to
86b7bd1
Compare
In response to #49377 (comment), I've opened #49390. With that being merged, I consider the following to be the remaining barriers to this work progressing:
While 1. is a common enough issue to make exploring alternatives a good idea, I wonder if 2. might be addressed by a change like #44275. |
86b7bd1
to
c9aa1d8
Compare
4ab4a53
to
33d611d
Compare
d90b3e0
to
927dbfc
Compare
The changes introduced by #49390 have changed the difference in performance to # frozen_string_literal: true
require "bundler/setup"
require "action_view"
require "benchmark/ips"
class Foo
include ActionView::Helpers
end
helpers = Foo.new
Benchmark.ips do |x|
x.report("tag") { helpers.tag("a", href: "foo") }
x.report("tag_builder") { helpers.tag.a(href: "foo") }
x.compare!
end
While that's still a degradation in performance, a benchmark one layer up the stack based on <%# app/views/documents/index.html.erb %>
<%= @documents.each do |document| %>
<% if @use_builder %>
<%= tag.a document.title, href: "/" %>
<% else %>
<%= tag "a", document.title, href: "/" %>
<% end %>
<p><%= document.content %></p>
<% end %> # app/controllers/documents_controller.rb
class DocumentsController < ApplicationController
class_attribute :use_builder, default: false
def index
@documents = Document.all
@use_builder = use_builder
end
end
# test/integration/documents_benchmark_test.rb
require "test_helper"
require "benchmark/ips"
class DocumentsIntegrationTest < ActionDispatch::IntegrationTest
test "index" do
get "/documents"
assert_equal 200, response.status
end
end
Benchmark.ips do |bm|
bm.report "tag" do
DocumentsController.use_builder = false
Minitest.run_one_method(DocumentsIntegrationTest, "test_index")
end
bm.report "tag_builder" do
DocumentsController.use_builder = true
Minitest.run_one_method(DocumentsIntegrationTest, "test_index")
end
bm.compare!
end The results:
|
5a54ba5
to
c4f668f
Compare
2871543
to
085f2df
Compare
085f2df
to
0ac3117
Compare
50eaddb
to
a493b2d
Compare
Follow-up to [rails#49371][] In the wake of the deprecation of `tag(:div)` in favor of `tag.div`, this commit replaces all calls made internally with the more modern syntax. This change is separate from the deprecation cycle, since there are **slight** behavioral changes, since the HTML output changes from self-closing elements like `<input />` to open void elements like `<input>`. [rails#49371]: rails#49371
a493b2d
to
5c99edf
Compare
Motivation / Background
Follow-up to #49371
In the wake of the deprecation of
tag(:div)
in favor oftag.div
, this commit replaces all calls made internally with the more modern syntax.This change is separate from the deprecation cycle, since there are slight behavioral changes, since the HTML output changes from self-closing elements like
<input />
to open void elements like<input>
.Checklist
Before submitting the PR make sure the following are checked:
[Fix #issue-number]