When this method was implemented
(https://github.com/rails/rails/pull/5016/files), `to_date` is called.
But this behavior was chagned refactoring
(https://github.com/rails/rails/pull/6452/files).
In the first commit, there were not test which asserts `to_date` is called.
I think trying `to_date` is more useful than trying `strftime`, because
we can write `"2015-01-01".to_date`. But first fix comments to match
actual behavior.
The thread_safe gem is being deprecated and all its code has been merged
into the concurrent-ruby gem. The new class, Concurrent::Map, is exactly
the same as its predecessor except for fixes to two bugs discovered
during the merge.
Earlier
when `data-disable-with` option is added direclty as in options then
```ruby
submit_tag("Save", { "data-disable-with" => "Processing..." })
# => <input type="submit" name="commit" value="Save" data-disable-with="Processing..." data-disable-with="Processing..." />
```
Now
when `data-disable-with` option is added direclty as in options then
```ruby
submit_tag("Save", { "data-disable-with" => "Processing..." })
# => <input type="submit" name="commit" value="Save" data-disable-with="Processing..." />
```
The `url_for` methods in `actionpack` and `actionview`
now make a copy of the provided options
before generating polymorphic paths or URLs.
The bug in the previous behavior
is most noticeable in a case like:
url_options = [:new, :post, param: 'value']
if current_page?(url_options)
css_class = "active"
end
link_to "New Post", url_options, class: css_class
In case of the form with nested fields_for, i. e.
<%= form_for :foos, url: root_path do |f| %>
<% @foos.each do |foo| %>
<%= f.fields_for 'foo[]', foo do |f2| %>
<%= f2.text_field :id %>
<% foo.bars.each do |bar| %>
<%= f2.fields_for 'bar[]', bar do |b| %>
<%= b.text_field :id %>
<% end %>
<% end %>
<% end %>
<% end %>
<%= f.submit %>
<% end %>
rails doesn't add index for 'foo' in the inner fields_for block, so field names
in the outer fields_for looks like "foos[foo][#{foo_index}][id]" and in the
inner "foos[foo[]][bar][#{bar_index}][id]". Submitting of such form leads to an
error like:
>ActionController::BadRequest (Invalid request parameters: expected Array
>(got Rack::QueryParser::Params) for param `foo'):
This commit adds indexes for the foos in the inner blocks, so field names
become "foos[foo][#{foo_index}][bar][#{bar_index}][id]" and submitting of such
form works fine as expected.
Fixes#15332
We don't need to pass the full hash just to pull one value out. It's
better to just pass the value that the method needs to know about so
that we can abstract it away from "options"
Before we were changing the state of the lookup_context for the duration
of the with_layout_format block, but since we already know the formats
we can just pass it explicitly.
Related with 8d7ce0f22a
Oops, I broke the build :(
Fixes the method signature of `assign_parameters` which now takes 6
arguments instead of 4. We likely will end up chaning the method
signature further so good to know this test is here.
Prevents double submission by making disable_with the default.
Default disable_with option will only be applied if user has not
specified her/his own disable_with option, whether that is in the
`data-disable-with` string form or the
`:data => { :disable_with => "Saving..." }` hash form. disable_with
will default to the value attribute.
A configuration option was added to opt out of this functionality if
the user so desires.
`config.action_view.automatically_disable_submit_tag = false`
With this change you will be able to specify any break sequence ("\r\n" for example) as an option.
adding proper documentation for break_sequence in ActionView::Helpers::TextHelper.word_wrap
adding some more documentation for word_wrap custom break sequence and making sure we use new hash syntax
If, doing a test like this:
```
class BugTest < ActionView::TestCase
def test_foo
omg
end
```
Will raise with:
```
RuntimeError: In order to use #url_for, you must include routing helpers
explicitly. For instance, `include
Rails.application.routes.url_helpers`.
```
Thats a bit confusing, as we are not calling url_for at all.
Browsers have not been limited to two connections per host for quite
some time now. With more connections allowed, the trade-off involved in
asset host distribution isn't so clear and it becomes more important
that developers measure actual performance before and after.
Using the string version of the class reference is now deprecated when
referencing middleware. This should be written as a class not as a string.
Deprecation warning that this change fixes:
```
DEPRECATION WARNING: Passing strings or symbols to the middleware
builder is deprecated, please change
them to actual class references. For example:
"ActionDispatch::ShowExceptions" => ActionDispatch::ShowExceptions
```
In the `tag_options` method, strings are continuously added to the
`output` string. Previously, we concatenated two strings and added the
generated string to `output`. By adding each of the strings to
`output`, one after the other, we will save the allocation of that
concatenated string.
Benchmark:
require 'benchmark/ips'
sep = " ".freeze
Benchmark.ips do |x|
x.report("string +") {
output = ""
output << sep + "foo"
}
x.report("string <<") {
output = ""
output << sep
output << "foo"
}
x.compare!
end
Results (Ruby 2.2.2):
Calculating -------------------------------------
string + 88.086k i/100ms
string << 94.287k i/100ms
-------------------------------------------------
string + 2.407M (± 5.8%) i/s - 12.068M
string << 2.591M (± 7.0%) i/s - 12.917M
Comparison:
string <<: 2591482.4 i/s
string +: 2406883.7 i/s - 1.08x slower
In the `tag_options` method an array is used to build up elements, then `Array#*` (which is an alias for `Array#join` is called to turn the array into a string. Instead of allocating an array to build a string, we can build the string we want from the beginning.
Saved: 121,743 bytes 893 objects
content_tag's first argument is will generate a string with an html tag so `:a` will generate: `<a></a>`. When this happens, the symbol is implicitly `to_s`-d so a new string is allocated. We can get around that by using a frozen string instead which
This change buys us 74,236 bytes of memory and 1,855 fewer objects per request.
The instrument method creates new strings, the most common action to instrument is "!render_template` so we can detect when that action is occurring and use a frozen string instead.
This change buys us 113,714 bytes of memory and 1,790 fewer objects per request.
No idea why on earth this hash key isn't already optimized by MRI, but it isn't. 💩
This change buys us 74,077 bytes of memory and 1,852 fewer objects per request.
When an unknonwn key is passed to the hash in `PRE_CONTENT_STRINGS` it returns nil, when you call "#{nil}" it allocates a new empty string. We can get around this allocation by using a default value `Hash.new { "".freeze }`. We can avoid the `to_sym` call by pre-populating the hash with a symbol key in addition to a string key.
We can freeze some strings when using Array#* to reduce allocations.
Array#join can take frozen strings.
This change buys us 86,600 bytes of memory and 1,857 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](b0e2da69f0/lib/let_it_go/core_ext/string.rb (L37)) please [give me a pull request to the appropriate file](b0e2da69f0/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)
Avoid computing the same fragment digest many times when looping over templates.
The cache is cleared on every request so template changes are still picked up.
This will silence deprecation warnings.
Most of the test can be changed from `render :text` to render `:plain`
or `render :body` right away. However, there are some tests that needed
to be fixed by hand as they actually assert the default Content-Type
returned from `render :body`.
This is another take at #14384 as we decided to wait until `master` is
targeting Rails 5.0. This commit is implementation-complete, as it
guarantees that all the public methods on the hash-inherited Parameters
are still working (based on test case). We can decide to follow-up later
if we want to remove some methods out from Parameters.
If a template includes `# Template Collection: ...` anywhere in its
source, that name will be used as the cache name for the partial that is
rendered for the collection.
This allows users to enable collection caching even if the template
doesn't start with `<% cache ... do %>`.
Moreover, the `# Template Collection: ...` notation is recognized in all
template types (and template types other than ERB can define a
resource_cache_call_pattern method to allow the `cache ... do` pattern
to be recognized too).
Adds the `virtual_path` option to `cache_fragment_name` so it can
be provided when needed.
That allows `cache_collection_render` to get the appropriate cache
key with the digest generated based on the template and prevent
collision with other templates that cache the same collection.
The regular expression which was used to detect partial templates that
begin with a `<% cache ... do %>` call missed some cases. This commits
attempts to improve the detection for some cases such as multi-line
comments at the beginning of the template. The different templates are
listed in two new unit test methods.
Note that specially crafted Ruby code can still evade such `cache`-call
detection: for example, a user might have its own method which itself
calls the Rails `cache` helper. In such a case, the template's code
doesn't start with a literal `cache` string and therefore will not be
eligible for collection caching.
This adds a script `bin/test` to most Rails framework components. The
script uses the rails minitest plugin to augment the runner.
See https://github.com/rails/rails/pull/19571 for details about the
plugin.
I did not yet add `bin/test` for activerecord, activejob and railties.
These components rely on specific setup performed in the rake-tasks.
`Tags::Base#select_content_tag`.
Previously, passing a falsey value to `include_blank` would be ignored if the
field was required, and a blank line would still be inserted. The following will
now raise instead of quietly failing:
`select("post", "category", %w(a required field), { include_blank: false }, required: 'required')`
Previously, when content_for is flushed, the content
was replaced directly by a new value in
ActionView::OutputFlow#set. The problem is this new
value passed to the method may not be an instance of
ActiveSupport::SafeBuffer.
This change forces the value to be set to a new
instance of ActiveSupport::SafeBuffer.
The patched test assumed the file system is case-sensitive, but that is not
necessarily the case. In particular, this test did not pass in the recommended
setup for the dev box, because the /vagrant shared folder is case-insensitive.
After looking at some gems that provide access to file system metadata I have
chosen to go with the check you can see in the patch because, albeit it's a bit
dirty creating a file, it is super easy to understand and clearly portable.
References https://github.com/rails/rails-dev-box/issues/102.
When one rendered a partial template without specifying an object
or a collection (e.g. <%= render partial: 'partial_name' %>), Rails
would make an object called :partial_name available in local_assigns.
I don't think this was the intended behavior, since no local variable
called 'partial_name' gets defined in the view.
I think we are better off leaving `sudo` outside of the documented
way of installing gems (`activerecord`, `actionpack`, …).
We don’t want newbies to think that `sudo` is required or, even worse, than
they actually have to type `[sudo] gem install`.
In most scenarios, `sudo` is not needed to install gems, and people who do
need it, probably already know about it.
What do you think? 😁