In this commit, we set the content-type to `text/html` in AbstractController if the `options[:html]` is true so that we don't include ActionView::Rendering into ActionController::Metal to set it properly.
I removed the if `options[:plain]` statement because `AbstractController#rendered_format` returns `Mime::TEXT` by default.
If AV::Rendering is mixed in, then `rendered_format` will be calculated
based on the current `lookup_context`, but calling `_process_format`
will set the `rendered_format` back on to the same lookup context where
we got the information in the first place!
Instead of getting information from an object, then setting the same
information back on to that object, lets just do nothing instead!
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"
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)
This sort of documentation style comes from 2009, probably due to
the merging of merb (see 38b608ecab (diff-017d9bc9b1d2bdae199b938d72c15488R120)).
Rails follows Ruby's convention to define which values are "truthy" or
"falsey", so there is no need to specify that the returned value must
strictly be a TrueClass or FalseClass. /cc @fxn
At present, if you skip a callback that hasn't been defined,
activesupport callbacks silently does nothing. However, it's easy to
mistype the name of a callback and mistakenly think that it's being
skipped, when it is not.
This problem even exists in the current test suite.
CallbacksTest::SkipCallbacksTest#test_skip_person attempts to skip
callbacks that were never set up.
This PR changes `skip_callback` to raise an `ArgumentError` if the
specified callback cannot be found.
As part of #19029, in future `skip_before_action`, `skip_after_action` and
`skip_around_action` will raise an ArgumentError if the specified
callback does not exist. `skip_action_callback` calls all three of these
methods and will almost certainly result in an ArgumentError. If anyone
wants to remove all three callbacks then they can still call the three
individual methods. Therefore let's deprecate `skip_action_callback` now
and remove it when #19029 is merged.
The new test/docs further explain the conflicts that can happen when
mixing `:if`/`:unless` options with `:only`/`:except` options in
`skip_before_action`.
The gist is that "positive" filters always have priority over negative
ones.
The previous commit already showed that `:only` has priority over `:if`.
This commit shows that `:if` has priority over `:except`.
For instance, the following snippets are equivalent:
```ruby
skip_before_action :some_callback, if: -> { condition }, except: action
```
```ruby
skip_before_action :some_callback, if: -> { condition }
```
Test case for using skip_before_filter with the options :only and :if
both present. In this case, the :if option will be ignored and :only
will be executed.
Closes#14549 (the commit was cherry-picked from there).
Introduce explicit way of halting callback chains by throwing :abort. Deprecate current implicit behavior of halting callback chains by returning `false` in apps ported to Rails 5.0. Completely remove that behavior in brand new Rails 5.0 apps.
Conflicts:
railties/CHANGELOG.md
This commit changes arguments and default value of CallbackChain's :terminator
option.
After this commit, Chains of callbacks defined **without** an explicit
`:terminator` option will be halted as soon as a `before_` callback throws
`:abort`.
Chains of callbacks defined **with** a `:terminator` option will maintain their
existing behavior of halting as soon as a `before_` callback matches the
terminator's expectation. For instance, ActiveModel's callbacks will still
halt the chain when a `before_` callback returns `false`.
Email does not support relative links since there is no implicit host. Therefore all links inside of emails must be fully qualified URLs. All path helpers are now deprecated. When removed, the error will give early indication to developers to use `*_url` methods instead.
Currently if a developer uses a `*_path` helper, their tests and `mail_view` will not catch the mistake. The only way to see the error is by sending emails in production. Preventing sending out emails with non-working path's is the desired end goal of this PR.
Currently path helpers are mixed-in to controllers (the ActionMailer::Base acts as a controller). All `*_url` and `*_path` helpers are made available through the same module. This PR separates this behavior into two modules so we can extend the `*_path` methods to add a Deprecation to them. Once deprecated we can use this same area to raise a NoMethodError and add an informative message directing the developer to use `*_url` instead.
The module with warnings is only mixed in when a controller returns false from the newly added `supports_relative_path?`.
Paired @sgrif & @schneems
Because it is more natural way to test substring inclusion. Also, in
this particular case it is much faster.
In general, using `Regexp.new str` for such kind of things is dangerous.
The string must be escaped, unless you know what you're doing. Example:
Regexp.new "\\" # HELLO WINDOWS
# RegexpError: too short escape sequence: /\/
The right way to do this is escape the string
Regexp.new Regexp.escape "\\"
# => /\\/
Here is the benchmark showing how faster `include?` call is.
```
require 'benchmark/ips'
Benchmark.ips do |x|
x.report('include?') { !"index".to_s.include? File::SEPARATOR }
x.report(' !~ ') { "index" !~ Regexp.new(File::SEPARATOR) }
end
__END__
Calculating -------------------------------------
include? 75754 i/100ms
!~ 21089 i/100ms
-------------------------------------------------
include? 3172882.3 (±4.5%) i/s - 15832586 in 5.000659s
!~ 322918.8 (±8.6%) i/s - 1602764 in 4.999509s
```
Extra `.to_s` call is needed to handle the case when `action_name` is
`nil`. If it is omitted, some tests fail.
We are going to deprecate only on Rails 5 to make easier plugin
maintainers support different Rails versions. Right now we are only
discouraging their usage.
This reverts commit 6c5f43bab8206747a8591435b2aa0ff7051ad3de.
Conflicts:
actionpack/CHANGELOG.md
This is a follow up to #15058.
This exception is regularly raised during development. This means it will enter
the user realm. We should provide an API page to show that this exception is public API.
/cc @schneems
This is an option for sending a raw content back to browser. Note that
this rendering option will unset the default content type and does not
include "Content-Type" header back in the response.
You should only use this option if you are expecting the "Content-Type"
header to not be set. More information on "Content-Type" header can be
found on RFC 2616, section 7.2.1.
Please see #12374 for more detail.
TLDR: always return an object that responds to the query methods from
request.format, and do not touch Mime::Type[] lookup to avoid bugs.
---
Long version:
The initial issue was about being able to do checks like
request.format.html? for request with an unknown format, where
request.format would be nil.
This is where the issue came from at first in #7837 and #8085
(merged in cba05887dc3b56a46a9fe2779b6b228880b49622), but the
implementation went down the path of adding this to the mime type
lookup logic.
This unfortunately introduced subtle bugs, for instance in the merged
commit a test related to send_file had to be changed to accomodate the
introduction of the NullType.
Later another bug was found in #13064, related to the content-type being
shown as #<Mime::NullType:...> for templates with localized extensions
but no format included. This one was fixed in #13133, merged in
43962d6ec50f918c9970bd3cd4b6ee5c7f7426ed.
Besides that, custom handlers were not receiving the proper template
formats anymore when passing through the rendering process, because of
the NullType addition. That was found while migrating an application
from 3.2 to 4.0 that uses the Markerb gem (a custom handler that
generates both text and html emails from a markdown template).
---
This changes the implementation moving away from returning this null
object from the mime lookup, and still fixes the initial issue where
request.format.zomg? would raise an exception for unknown formats due to
request.format being nil.
By default, variants in the templates will be picked up if a variant is set
and there's a match. The format will be:
app/views/projects/show.html.erb
app/views/projects/show.html+tablet.erb
app/views/projects/show.html+phone.erb
If request.variant = :tablet is set, we'll automatically be rendering the
html+tablet template.
In the controller, we can also tailer to the variants with this syntax:
class ProjectsController < ActionController::Base
def show
respond_to do |format|
format.html do |html|
@stars = @project.stars
html.tablet { @notifications = @project.notifications }
html.phone { @chat_heads = @project.chat_heads }
end
format.js
format.atom
end
end
end
The variant itself is nil by default, but can be set in before filters, like
so:
class ApplicationController < ActionController::Base
before_action do
if request.user_agent =~ /iPad/
request.variant = :tablet
end
end
end
This is modeled loosely on custom mime types, but it's specifically not
intended to be used together. If you're going to make a custom mime type,
you don't need a variant. Variants are for variations on a single mime
types.
The methods:
* #render_to_body
* #render_to_string
* #_normalize_render
Haven't had anything specyfic to ActionView. This was common code which should belong to AbstractController
:only and :except options for controller filters are now added before
:if and :unless. This prevents running :if and :unless procs when not
on the specified. Closes#11786.
When helper try to require missing file rails will throw exception about
missing helper.
# app/helpers/my_helper.rb
require 'missing'
module MyHelper
end
And when we try do load helper
class ApplicationController
helper :my
end
Rails will throw exception. This is wrong because there is a helper
file.
Missing helper file helpers/my_helper.rb
Now when helper try to require non-existed file rails will throw proper
exception.
No such file to load -- missing
When setting the layout either by referencing a method or supplying a
Proc there is no way to fall back to the default lookup behavior if
desired. This patch allows fallback to the layout lookup behavior when
returning nil from the proc or method.
The conditional_layout? method is not for public use and doesn't
actually do what the documentation suggested it does. It's actually
used to determine whether or not to use the explicit layout definition
defined in a controller or use the implicit layout definition.
Also documentation was added for the action_has_layout? method which
acts as a master switch for disabling the layout for the current
action. This method was added so that action caching didn't depend
on accessing layout internals but is also used by third-parties,
most notably the [Hobo][1] application.
[1]: https://github.com/hobo/hobo
* Avoid calling class_eval when not needed
* Remove helpers_path attr accessor, it's defined as a class attribute a
few lines later
* Avoid creating extra arrays when finding helpers, use flat_map and sort!
* Remove not required refer variable when redirecting :back
Assuming the type ":touch", Collector.new was calling
send(:touch), which instead of triggering method_missing
and generating a new collector method, actually
invoked the private method `touch` inherited from
Object.
By generating the method for each mime type as it
is registered, the private methods on Object can
never be reached by `send`, because the `Collector`
will have them before `send` is called on it.
To do this, a callback mechanism was added to Mime::Type
This allows someone to add a callback for whenever
a new mime type is registered. The callback then
gets called with the new mime as a parameter.
This is then used in AbstractController::Collector
to generate new collector methods after each mime
is registered.
The `path` method on missing helper errors is inconsistent with the
implementation on LoadError in Ruby 2.0. Wrap up the missing helper
exceptions so that the inconsistent behavior is mirrored in Ruby 2.0
(until we can figure out *why* it's inconsistent).
This reverts commit fa6d921e11363e9b8c4bc10f7aed0b9faffdc33a.
Reason: Not a fan of such massive changes. We usually close such changes
if made to Rails master as a pull request. Following the same principle
here and reverting.
[ci skip]
For future reference, this is the regex I used: ^\s*#\s*\n(?!\s*#). Replace
with the first match, and voilà! Note that the regex matches a little bit too
much, so you probably want to `git add -i .` and go through every single diff
to check if it actually should be changed.
Rails will now use your default layout (such as "layouts/application") when you specify a layout with `:only` and `:except` condition, and those conditions fail.
For example, consider this snippet:
class CarsController
layout 'single_car', :only => :show
end
Rails will use 'layouts/single_car' when a request comes in `:show` action, and use 'layouts/application' (or 'layouts/cars', if exists) when a request comes in for any other actions.