| Commit message (Collapse) | Author | Age | Files | Lines |
|
|
| |
`Forwardable` has been used in the past
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
When generating the url for a mounted engine through its proxy, the path should be the sum of three parts:
1. Any `SCRIPT_NAME` request header or the value of `ActionDispatch::Routing::RouteSet#relative_url_root`.
2. A prefix (the engine's mounted path).
3. The path of the named route inside the engine.
Since commit https://github.com/rails/rails/commit/44ff0313c121f528a68b3bd21d6c7a96f313e3d3, this has been broken. Step 2 has been changed to:
2. A prefix (the value of `ActionDispatch::Routing::RouteSet#relative_url_root` + the engine's mounted path).
The value of `ActionDispatch::Routing::RouteSet#relative_url_root` is taken into account in step 1 of the route generation and should be ignored when generating the mounted engine's prefix in step 2.
This commit fixes the regression by having `ActionDispatch::Routing::RouteSet#url_for` check `options[:relative_url_root]` before falling back to `ActionDispatch::Routing::RouteSet#relative_url_root`. The prefix generating code then sets `options[:relative_url_root]` to an empty string. This empty string is used instead of `ActionDispatch::Routing::RouteSet#relative_url_root` and avoids the duplicate `relative_url_root` value in the final result.
This resolves #20920 and resolves #21459
|
|
|
|
|
|
|
|
|
|
| |
Controllers should always have a request and response when responding.
Since we make this The Rule(tm), then controllers don't need to be
somewhere in limbo between "asking a response object for a rack
response" or "I, myself contain a rack response". This duality leads to
conditionals spread through the codebase that we can delete:
* https://github.com/rails/rails/blob/85a78d9358aa728298cd020cdc842b55c16f9549/actionpack/lib/action_controller/metal.rb#L221-L223
|
|
|
|
| |
This saves a lambda and request allocation on each request.
|
|
|
|
|
| |
controllers should always go through the `action` class method so that
their middleware is respected.
|
|
|
|
|
| |
now the caller can just treat it like a regular controller even though
it will return a 404
|
|
|
|
|
| |
the dispatcher class isn't configurable anymore, so pull up allocation
to the method that needs it.
|
|
|
|
|
|
| |
Now that we don't have subclasses depending on this method (they augment
the request class instead of the dispatch class) we can remove this
method and directly ask the request object for the controller class
|
| |
|
|
|
|
| |
we don't need it anymore. We always use the same dispatcher in tests.
|
|
|
|
|
|
| |
controller class resolution has been moved to the request object, so we
should override that method instead of relying on the RouteSet to
generate the controller class.
|
| |
|
|
|
|
|
|
|
|
|
| |
Since none of the action pack tests failed without this conditional it
didn't seem necessary. This fixes the build because it correctly returns
a 404 instead of a 500 for the asset routes test.
Test that was failing was in the `assets_test.rb` file and was the test
named `test_assets_routes_are_not_drawn_when_compilation_is_disabled`.
|
|
|
|
|
|
|
|
|
|
| |
This refactoring moves the controller class name that was on the route
set to the request. The purpose of this refactoring is for changes we
need to move controller tests to integration tests, mainly being able to
access the controller on the request instead of having to go through
the router.
[Eileen M. Uchitelle & Aaron Patterson]
|
|
|
|
|
|
|
| |
`ActiveSupport::Dependencies.constantize(const_name)` calls
`Reference.new` which is defined as
`ActiveSupport::Dependencies.constantize(const_name)` meaning this call
is already cached and we're doing caching that isn't necessary.
|
|
|
|
|
| |
nobody should be touching the routes hash without going through the
NamedRouteCollection object.
|
|
|
|
|
| |
The outer router object already keeps a hash of named routes, so we
should just use that.
|
|
|
|
|
| |
refactor the tests with a backwards compatible method call so we can rm
add_route2 from the journey router
|
|
|
|
|
| |
then we can let the mapping object derive stuff that the Route object
needs.
|
|
|
|
|
| |
now that we aren't doing options manipulations, we can just pass the
mapping object down and read values from it.
|
|
|
|
|
| |
now we don't need to add it to a hash and delete it from the hash later
just to pass it around
|
|
|
|
| |
we don't need to keep adding it and deleting if from hashes.
|
|
|
|
|
| |
It just constructs a Path::Pattern object with the AST that it already
has
|
|
|
|
|
| |
This was a useless object. We can just directly construct a
Path::Pattern object without a Strexp object.
|
|
|
|
|
| |
the caller already has it, there is no reason to pack it in to an object
and just throw that object away.
|
| |
|
|
|
|
|
| |
we always pass all parameters, so there is no reason to provide default
arguments.
|
|
|
|
|
| |
This method raises conditionally not always so we should not documment
as it always raise.
|
| |
|
|
|
|
|
| |
We should return when the contoller key is not present or if the
controller doesn't exist and we didn't raised an error.
|
|
|
|
|
|
|
| |
we need to get a grip on what `scope` actually does. This commit
removes some of the internal calls to `scope`. Eventually we should add
public facing methods that provide the API that `scope` is trying to
accomplish.
|
|
|
|
|
|
| |
`prepare_params!` would raise an exception if `params` wasn't
initialized, so it must always be available. Remove the existence
conditional from the `controller` method.
|
|
|
|
|
| |
The method we called already has the conditional we need. Just add an
else block so that we don't need two tests.
|
|
|
|
|
|
|
| |
`Dispatcher` doesn't need to hold on to the defaults hash. It only used
the hash to determine whether or not it should raise an exception if
there is a name error. We can pass that in further up the stack and
alleviate Dispatcher from knowing about that hash.
|
|\
| |
| | |
replace each with each_key when only the key is needed
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
Using each_key is faster and more intention revealing.
Calculating -------------------------------------
each 31.378k i/100ms
each_key 33.790k i/100ms
-------------------------------------------------
each 450.225k (± 7.0%) i/s - 2.259M
each_key 494.459k (± 6.3%) i/s - 2.467M
Comparison:
each_key: 494459.4 i/s
each: 450225.1 i/s - 1.10x slower
|
| | |
|
| |
| |
| |
| | |
scope so that they are available to subclasses.
|
|/ |
|
|\
| |
| | |
Remove duplicated `Array#to_param`
|
| |
| |
| |
| |
| | |
`Array#to_param` is defind in active_support/core_ext/object/to_query.rb,
so we can call `to_param` if value is_a Array.
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
While the readability may be slightly worse, the speed improvement is
significant: Twice as fast when there's no leading "/" to remove, and
over 4 times as fast when there is a leading "/".
Benchmark:
require 'benchmark/ips'
def match(controller)
if controller
if m = controller.match(/\A\/(?<controller_without_leading_slash>.*)/)
m[:controller_without_leading_slash]
else
controller
end
end
end
def start_with(controller)
if controller
if controller.start_with?('/'.freeze)
controller[1..-1]
else
controller
end
end
end
Benchmark.ips do |x|
x.report("match") { match("no_leading_slash") }
x.report("start_with") { start_with("no_leading_slash") }
x.compare!
end
Benchmark.ips do |x|
x.report("match") { match("/a_leading_slash") }
x.report("start_with") { start_with("/a_leading_slash") }
x.compare!
end
Result (Ruby 2.2.2):
Calculating -------------------------------------
match 70.324k i/100ms
start_with 111.264k i/100ms
-------------------------------------------------
match 1.468M (± 7.1%) i/s - 7.314M
start_with 3.787M (± 3.5%) i/s - 18.915M
Comparison:
start_with: 3787389.4 i/s
match: 1467636.4 i/s - 2.58x slower
Calculating -------------------------------------
match 36.694k i/100ms
start_with 86.071k i/100ms
-------------------------------------------------
match 532.795k (± 4.7%) i/s - 2.679M
start_with 2.518M (± 5.8%) i/s - 12.566M
Comparison:
start_with: 2518366.8 i/s
match: 532794.5 i/s - 4.73x slower
|
| |
| |
| |
| |
| |
| | |
If we don't mutate the `recall` hash, then there's no reason to duplicate it. While this change doesn't get rid of that many objects, each hash object it gets rid of was massive.
Saves 888 string objects per request, 206,013 bytes (thats 0.2 mb which is kinda a lot).
|
| |
| |
| |
| |
| |
| | |
Instead of calling `sub` on every link_to call for controller, we can detect when the string __needs__ to be allocated and only then create a new string (without the leading slash), otherwise, use the string that is given to us.
Saves 888 string objects per request, 35,524 bytes.
|
| |
| |
| |
| | |
Saves 888 string objects per request.
|
| |
| |
| |
| |
| |
| |
| |
| | |
When generating a url with `url_for` the hash of arguments passed in, is dup-d and merged a TON. I wish I could clean this up better, and might be able to do it in the future. This change removes one dup, since it's literally right after we just dup-d the hash to pass into this constructor.
This may be a breaking, change but the tests pass...so :shipit: we can revert if it causes problems
This change buys us 205,933 bytes of memory and 887 fewer objects per request.
|
|/
|
|
|
|
|
|
| |
In handle_positional_args `Array#-=` is used which allocates a new array. Instead we can iterate through and delete elements, modifying the array in place.
Also `Array#take` allocates a new array. We can build the same by iterating over the other element.
This change buys us 106,470 bytes of memory and 2,663 fewer objects per request.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
I wrote a utility that helps find areas where you could optimize your program using a frozen string instead of a string literal, it's called [let_it_go](https://github.com/schneems/let_it_go). After going through the output and adding `.freeze` I was able to eliminate the creation of 1,114 string objects on EVERY request to [codetriage](codetriage.com). How does this impact execution?
To look at memory:
```ruby
require 'get_process_mem'
mem = GetProcessMem.new
GC.start
GC.disable
1_114.times { " " }
before = mem.mb
after = mem.mb
GC.enable
puts "Diff: #{after - before} mb"
```
Creating 1,114 string objects results in `Diff: 0.03125 mb` of RAM allocated on every request. Or 1mb every 32 requests.
To look at raw speed:
```ruby
require 'benchmark/ips'
number_of_objects_reduced = 1_114
Benchmark.ips do |x|
x.report("freeze") { number_of_objects_reduced.times { " ".freeze } }
x.report("no-freeze") { number_of_objects_reduced.times { " " } }
end
```
We get the results
```
Calculating -------------------------------------
freeze 1.428k i/100ms
no-freeze 609.000 i/100ms
-------------------------------------------------
freeze 14.363k (± 8.5%) i/s - 71.400k
no-freeze 6.084k (± 8.1%) i/s - 30.450k
```
Now we can do some maths:
```ruby
ips = 6_226k # iterations / 1 second
call_time_before = 1.0 / ips # seconds per iteration
ips = 15_254 # iterations / 1 second
call_time_after = 1.0 / ips # seconds per iteration
diff = call_time_before - call_time_after
number_of_objects_reduced * diff * 100
# => 0.4530373333993266 miliseconds saved per request
```
So we're shaving off 1 second of execution time for every 220 requests.
Is this going to be an insane speed boost to any Rails app: nope. Should we merge it: yep.
p.s. If you know of a method call that doesn't modify a string input such as [String#gsub](https://github.com/schneems/let_it_go/blob/b0e2da69f0cca87ab581022baa43291cdf48638c/lib/let_it_go/core_ext/string.rb#L37) please [give me a pull request to the appropriate file](https://github.com/schneems/let_it_go/blob/b0e2da69f0cca87ab581022baa43291cdf48638c/lib/let_it_go/core_ext/string.rb#L37), or open an issue in LetItGo so we can track and freeze more strings.
Keep those strings Frozen
![](https://www.dropbox.com/s/z4dj9fdsv213r4v/let-it-go.gif?dl=1)
|
| |
|
| |
|