1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

significant speedup of AC::Parameters#permit

The current implementation of AC::Parameters#permit builds permitted hashes and
then calls permit! on them.

This filtering is recursive, so we call permit! on terminal branches, but then
ascendants call permit! on themselves when the recursion goes up the stack,
which recurses all the way down again because permit! is recursive itself.
Repeat this for every parent node and you get some scary O-something going on
that I don't even want to compute.

Instead, since the whole point of the permit recursion is to build permitted
hashes along the way and at that point you know you've just come up with a
valid filtered version, you can already switch the toggle on the spot.

I have seen 2x speedups in casual benchmarks with small structures. As the
previous description shows, the difference in performance is going to be a
function of the nesting.

Note that that the involved methods are private and used only by permit.
This commit is contained in:
Xavier Noria 2016-11-12 12:33:37 +01:00
parent 5647d85440
commit 26dd9b26ab
2 changed files with 8 additions and 1 deletions

View file

@ -398,7 +398,8 @@ module ActionController
unpermitted_parameters!(params) if self.class.action_on_unpermitted_parameters unpermitted_parameters!(params) if self.class.action_on_unpermitted_parameters
params.permit! params.permitted = true
params
end end
# Returns a parameter for the given +key+. If not found, # Returns a parameter for the given +key+. If not found,
@ -816,6 +817,7 @@ module ActionController
# Filter this one out. # Filter this one out.
end end
end end
sanitized.permitted = true
end end
end end

View file

@ -187,6 +187,11 @@ class ParametersPermitTest < ActiveSupport::TestCase
permitted = params.permit(:username, preferences: {}, hacked: {}) permitted = params.permit(:username, preferences: {}, hacked: {})
assert permitted.permitted?
assert permitted[:preferences].permitted?
assert permitted[:preferences][:font].permitted?
assert permitted[:preferences][:dubious].all?(&:permitted?)
assert_equal "fxn", permitted[:username] assert_equal "fxn", permitted[:username]
assert_equal "Marazul", permitted[:preferences][:scheme] assert_equal "Marazul", permitted[:preferences][:scheme]
assert_equal "Source Code Pro", permitted[:preferences][:font][:name] assert_equal "Source Code Pro", permitted[:preferences][:font][:name]