`ActionView::Helpers::NumberHelper` methods are thin wrappers over
`ActiveSupport::NumberHelper` methods, which are well documented. Thus
this commit points `ActionView::Helpers::NumberHelper` method docs to
`ActiveSupport::NumberHelper` methods instead of duplicating those docs.
Provide examples for rendering objects that respond to `render_in`. Also
highlight that the object can also define a `#format` method to control
how the rendered String should be treated.
Add test coverage for both Action View's and Action Pack's support for
`render` with `:renderable` options.
Now that we dropped support for Ruby 2.7, we no longer
need to check if variables are defined before accessing them
to avoid the undefined variable warning.
Now that we no longer support Ruby 2.7, many `ruby2_keyword` calls
can be eliminated.
The ones that are left could be eliminated but would end up substantially
slower or more compliacated so I left them for now.
This provides a shortcut for setting a Content Security Policy nonce on
a stylesheet_link_tag.
Co-authored-by: AJ Esler <ajesler@users.noreply.github.com>
This seems to be making a pair with `#render_partial` but in reality
it's no longer refered to from anywhere. Since it is marked with
nodoc, I propose to get rid of it.
As far as I can tell from my non-comprehensive research,
this method was introduced in the commit b735761,
became practically private in f984907 and unused in 1bc0a59.
To integrate with [rails-dom-testing][] and its selector assertions,
`ActionView::TestCase` [defines a `#document_root_element`
method][document_root_element] that parses the HTML into a fully valid
HTML document and returns the "root".
In the case of most Action View partials rendered with `render partial:
"..."`, the resulting document would be invalid, so its constituent
parts (its `<html>`, `<head>`, and `<body>` elements) are synthesized in
during the parsing process. This results in a document whose _contents_
are equivalent to the original HTML string, but whose structure is not.
To share a concrete example:
```ruby
irb(main):002:0> rendered = "<h1>Hello world</h1><h2>Goodbye world</h2>"
=> "<h1>Hello world</h1><h2>Goodbye world</h2>"
irb(main):003:0> root = Rails::Dom::Testing.html_document.parse(rendered).root
=>
#(Element:0x57080 {
...
irb(main):004:0> rendered.to_s
=> "<h1>Hello world</h1><h2>Goodbye world</h2>"
irb(main):005:0> root.to_s
=> "<html><head></head><body><h1>Hello world</h1><h2>Goodbye world</h2></body></html>"
irb(main):006:0> rendered.to_s == root.to_s
=> false
```
Prior to this commit, the parsed HTML content returned from calling
`rendered.html` relied on the same mechanisms as
`#document_root_element`, and parsed the HTML fragment into a full
document, with a synthesized `<html>` element as its root. The
`rendered.html` value should reflect the content that was **rendered**
by the partial, and should not behave the same as
`#document_root_element`.
When the parsing class is changed from [Nokogiri::XML::Document][] to
[Nokogiri::XML::DocumentFragment][], the returned value reflects the
same **exact** content as what was rendered.
To elaborate on the previous example:
```ruby
irb(main):007:0> fragment = Rails::Dom::Testing.html_document_fragment.parse(rendered)
=>
#(DocumentFragment:0x62ee4 {
...
irb(main):008:0> fragment.to_s
=> "<h1>Hello world</h1><h2>Goodbye world</h2>"
irb(main):009:0> rendered.to_s == fragment.to_s
=> true
```
This commit changes the default `rendered.html` behavior to rely on
`Nokogiri::XML::DocumentFragment` instead of `Nokogiri::XML::Document`.
[Nokogiri::XML::Document]: https://nokogiri.org/rdoc/Nokogiri/XML/Document.html
[Nokogiri::XML::DocumentFragment]: https://nokogiri.org/rdoc/Nokogiri/XML/DocumentFragment.html
[document_root_element]: https://github.com/rails/rails-dom-testing/blob/v2.2.0/lib/rails/dom/testing/assertions/selector_assertions.rb#L75
Closes#49818
Renames `ActionView::TestCase::Behavior::Content` to
`RenderedViewContent`, with the goal of making it more of an internal
implementation detail that's unlikely to collide with an
application-side `::Content` class.
The `RenderedView`-prefix mirrors the module's `RenderedViewsCollection`
class. Since the intention is to treat it as a private implementation
detail, `RenderedViewContent` is marked with `:nodoc:`.
Along with the rename, this commit also modifies the class inheritance,
replacing the `SimpleDelegator` superclass with `String`. [String.new][]
accepts a `String` positional argument in the same way as
`SimpleDelegator.new` accepts a delegate object positional argument.
Sharing the `String` superclass also makes it a good candidate for being
passed to [Capybara.string][] (and [Capybara::Node::Simple.new][]) like
the documentation suggests.
[Capybara.string]: https://github.com/teamcapybara/capybara/blob/3.39.2/lib/capybara.rb#L212-L242
[Capybara::Node::Simple.new]: https://github.com/teamcapybara/capybara/blob/3.39.2/lib/capybara/node/simple.rb#L23
[String.new]: https://ruby-doc.org/core/String.html#method-c-new
Apparently it had not been clear what visibility they should assume
when they were initially created at https://github.com/rails/rails/pull/35265,
then a big refactoring took place at https://github.com/rails/rails/pull/38594
after which they remain intact.
So I think they can now become properly private as they are nodoc and
not refered to but from within the same class.
Also perform two autocorrects with `bundle exec rubocop -A`:
- fixes a new case of [`Style/RedundantReturn`][1]
- fixes a new case of [`Performance/StringInclude`][2]
[1]: 146b1c2e33
[2]: 3158bbb9f6
Co-authored-by: David Heinemeier Hansson <david@basecamp.com>
Until now, Rails only droped compatibility with older
rubies on new majors, but I propose to change this policy
because it causes us to either keep compatibility with long
EOLed rubies or to bump the Rails major more often, and to
drop multiple Ruby versions at once when we bump the major.
In my opinion it's a bad alignments of incentives. And we'd
be much better to just drop support in new minors whenever they
go EOL (so 3 years).
Also Ruby being an upstream dependency, it's not even
a semver violation AFAICT.
Since Rails 7.2 isn't planned before a few months, we
can already drop Ruby 3.0 as it will be EOL in March.
Since `ActionText::Content` wraps an `ActionText::Fragment`, and
`ActionText::Fragment` wraps a `Nokogiri::XML::DocumentFragment`, then
`ActionText::Content` should be able to rely on the newer Ruby pattern
matching introduced by [nokogiri@1.16.0][] (mainly the
[DocumentFragment#deconstruct][] method):
```ruby
content = ActionText::Content.new <<~HTML
<h1>Hello, world</h1>
<div>The body</div>
HTML
content => [h1, div]
assert_pattern { h1 => { content: "Hello, world" } }
assert_pattern { div => { content: "The body" } }
```
The implementation change relies on delegating from `Content` to
`Fragment`, and from `Fragment` to `DocumentFragment#elements` (to
deliberately exclude text nodes).
[nokogiri@1.16.0]: https://nokogiri.org/CHANGELOG.html?h=pattern
[DocumentFragment#deconstruct]: https://nokogiri.org/rdoc/Nokogiri/XML/DocumentFragment.html?h=deconstruct#method-i-deconstruct
Round mode option was added in 7905bdfd8b
but it was documented in active supports number helper only. Action
views number helper is using active supports helper and accepts
round_mode option so it should be documented there also.
Examples are also unified and it should be more clear that they return
string and not a number.
[ci skip]
To assert the expected number of queries are made, Rails internally uses
`assert_queries` and `assert_no_queries`. These assertions can be
useful in applications as well.
By extracting these assertions to a module, the assertions can be
included where required.
These assertions are added to `ActiveSupport::TestCase` when
ActiveRecord is defined.
ActiveStorage, ActionView and ActionText are using this module now as
well, instead of duplicating the implementation.
The internal ActiveRecord::TestCase, used for testing ActiveRecord,
implements these assertions as well. However, these are slighlty more
advanced/complex and use the SQLCounter class. To keep things simple,
for now this implementation isn't used.
This is a continuation of https://github.com/rails/rails/pull/46875
The behavior of looking up the class method when `to: :class` is passed
is a bit error prone because it silently degrades.
By passing the expected owner of the delegated method, we can be more
strict, and also generate a delegator in a module rather than having
to do it at inclusion time.
I made this argument private API because we want it in Rails, but
I'm worried it might be a bit too sharp for public API. I can
be convinced otherwise though.
Define the `ActionView::Helpers::FormBuilder` methods that wrap the
`@template` instance methods inside an
`ActiveSupport::CodeGenerator.batch` call so that the underlying `class`
extensions aren't invoked more than once.
This portrays the return values more accurately and, in some cases,
fixes syntax highlighting when using the upcoming version of SDoc
(thanks to its heuristic for detecting Ruby code vs HTML code).
According to the [HTML5 Spec][1]
> Void elements can't have any contents (since there's no end tag, no
> content can be put between the start tag and the end tag).
Up to this point, the only special handling of void elements has been to
use ">" to close them instead of "/>" (which is optional but valid
according to the spec)
> Then, if the element is one of the void elements, ... , then there may
> be a single U+002F SOLIDUS character (/), ... . On void elements, it
> does not mark the start tag as self-closing but instead is unnecessary
> and has no effect of any kind.
This commit deprecates the ability to pass content (either through the
positional "content" parameter or a block) to a void element since it is
not valid according to the Spec. This has the benefit of both
encouraging more correct HTML generation, and also simplifying the
method definition of void elements once the deprecation has been
removed.
This commit additionally tweaks the signature of "void_tag_string"
slightly with two changes. The first change is renaming it to be
"self_closing_tag_string". This is more accurate than "void_tag_string"
because the definition of "void element" is more specific and has more
requirements than "self closing element". For example, tags in the SVG
namespace _can_ be self closing but the "/" at the end of the start tag
is _not_ optional because they are not void elements. The second change
to this method is swapping from a boolean "self_closing" parameter to a
string "tag_suffix" parameter. This enables the void element method
definition to specialize the tag_suffix (to just ">") without either
void elements or self closing elements having to pay the runtime cost of
the self_closing conditional since we know at method definition time
which suffix each type of tag should use.
[1]: https://html.spec.whatwg.org/multipage/syntax.html#void-elements
Just a wee bit of visualization changes to make it more explicitly clear what is being passed (a quoted number)
Co-authored-by: Jonathan Hefner <jonathan@hefner.pro>
This adds `linguist-generated` and `linguist-vendored` attributes where
appropriate to suppress the files in diffs and exclude the files from
the project's language stats on GitHub.
See https://github.com/github/linguist for more information.
Prior to this commit, if `app/javascript/rails-ujs/index.js`
contained a syntax error, `JavascriptPackageTest` would still pass
because `system "yarn build"` would simply return `false` and the
compiled output would not change. This commit adds `exception: true` to
the `system` call so that an error will be raised if `yarn build` fails.
This fixes a few issues with the formatting of the API documentation for
`ActionView::TestCase::Behavior::ClassMethods#register_parser`:
* Use `h4` headings instead of `h3` headings. SDoc renders method
signatures as `h3` headings, so subheadings such as "Examples" should
use `h4`.
* Replace "Arguments" heading with "Parameters". "Parameters" are
elements of function's signature, whereas "arguments" are elements of
a function call. The API documentation for other methods follows this
convention.
* Format parameters as term list.
* Fix indentation of pre-registered parser lists to render them as lists
instead of as code.
* Miscellaneous rewording, reorganization, and additional monospace
formatting.
Previously, both the `@rendered_format` and
`@marked_for_same_origin_verification` instance variables would be
assigned to instances of `ActionView::Base`, making them accessible in
view templates. However, these instance variables are really internal to
the controller and result in extra string allocations because the `@`
gets stripped and readded when going through the assignment.
This commit prefixes the variables with an underscore to help indicate
that they are internal, and then adds them to the list of
`_protected_ivars` to prevent assigning them when rendering templates.
Co-authored-by: Jean Boussier <jean.boussier@gmail.com>
Co-authored-by: Jonathan Hefner <jonathan@hefner.pro>
Fix: https://github.com/rails/rails/pull/49780
Fix: https://github.com/rails/rails/issues/49761
`CollectionRenderer` implictly inject `<name>_counter` and `<name>_iteration`
locals, but in the overwhelming majority of cases they aren't used.
So when the rendered template has strict locals we shouldn't require
these to be declared, and if they aren't we should simply not pass them.
Co-Authored-By: HolyWalley <yakau@hey.com>
An issue was recently raised that users were seeing an error when
upgrading `@rails/ujs` to 7.1.0+:
```
Uncaught Error: rails-ujs has already been loaded!
```
Generally this issue appears due to the difference in how rails-ujs is
expected to behave in a pure sprockets environment (js appending) vs a
bundled environment (webpack, esbuild, etc.). The sprockets environment
is supposed to call start() automatically, while the bundled environment
is supposed to require users to import and call start() themselves.
As part of the transition from coffeescript to javascript, a condition
was added that was intended to detect whether the current environment
was a bundler so that it would only call start() when in sprockets.
However, this condition is not working as expected, and I was able to
reproduce the error appearing when using rails-ujs with importmaps and
esbuild. Interestingly, the issue did not appear when using Webpack as a
bundler.
I believe the best fix here is to make the condition very explicit.
Since sprockets users should not be using the esm version of rails-ujs,
we can use the rollup replace plugin to explicitly opt the esm bundle
out of _ever_ calling start() automatically. This works because terser
will run after the replace plugin and remove the whole condition as dead
code (since it sees true == false).
Co-authored-by: Ryunosuke Sato <tricknotes.rs@gmail.com>
Ref: https://github.com/rails/rails/pull/47194#issuecomment-1760334146
They both give the buffer as return value of the capture block
which confuses the `capture` helper.
Ideally we wouldn't have to check for that, but it's
an acceptable tradeoff for backward compatibility.
The `ActionView::Helpers::TagHelper::TagBuilder` class renders HTML
elements based on the methods invoked on it. For example, `tag.input`
will render an `<input>` element, while `tag.turbo_frame` will render a
`<turbo-frame>` element.
The magic of the class is rooted in its definition of `#method_missing`.
The current implementation bakes-in special treatment of void HTML
elements (for example: `<input>`) and self-closing SVG elements (for
example: `<use />`). Despite its ahead-of-time knowledge of these
element names, calls to corresponding methods `tag.input` and `tag.use`
still rely on `#method_missing`.
This has performance implications.
This commit defines a new `TagBuilder.define_void_element` class method
to dynamically define methods for each known element. Then, the class
invokes the method for each element name in `HTML_VOID_ELEMENTS` and
`SVG_SELF_CLOSING_ELEMENTS`.
Calls to `.define_void_element` and `.define_self_closing_element` makr
`HTML_VOID_ELEMENTS` and `SVG_SELF_CLOSING_ELEMENTS` unnecessary, so
this commit removes those constant definitions.
Additionally, this call removes calls to
`TagHelper.ensure_valid_html5_tag_name` from the `TagBuilder` defined
element methods, since they're known ahead of time to be valid HTML.
Instead, only call `ensure_valid_html5_tag_name` from within the
`method_missing` calls, since those are determined at runtime and are
uncontrolled.
By cutting out the reliance on method missing, calls to `TagBuilder`
methods (like `tag.input`) become comparable to calls to the `tag` view
helper with positional arguments (like `tag(:input)`).
```
❯ ruby bench.rb
Warming up --------------------------------------
tag 73.438k i/100ms
tag_builder 79.910k i/100ms
Calculating -------------------------------------
tag 732.467k (± 0.9%) i/s - 3.672M in 5.013504s
tag_builder 810.981k (± 0.8%) i/s - 4.075M in 5.025632s
Comparison:
tag_builder: 810981.5 i/s
tag: 732467.4 i/s - 1.11x (± 0.00) slower
```
The results were from the following benchmark rendering void (`<input>`)
elements:
```ruby
# frozen_string_literal: true
require "bundler/setup"
require "action_view"
require "minitest/autorun"
require "benchmark/ips"
class Foo
include ActionView::Helpers
end
helpers = Foo.new
Benchmark.ips do |x|
x.report("tag") { helpers.tag("input", value: "foo") }
x.report("tag_builder") { helpers.tag.input(value: "foo") }
x.compare!
end
```
Similar to `tag.input` (a void HTML element), calls to `tag.div` are
become somewhat comparable to `tag("div")`:
```
❯ ruby bench.rb
Warming up --------------------------------------
content_tag 59.548k i/100ms
tag_builder 51.215k i/100ms
Calculating -------------------------------------
content_tag 595.067k (± 0.5%) i/s - 2.977M in 5.003570s
tag_builder 505.553k (± 2.2%) i/s - 2.561M in 5.067704s
Comparison:
content_tag: 595067.5 i/s
tag_builder: 505552.6 i/s - 1.18x (± 0.00) slower
```
The following benchmarks were collected to compare `tag("turbo-frame")`
(an unknown custom HTML element) and `tag.turbo_frame`:
```
❯ ruby bench.rb
Warming up --------------------------------------
content_tag 56.152k i/100ms
tag_builder 49.207k i/100ms
Calculating -------------------------------------
content_tag 561.134k (± 0.5%) i/s - 2.808M in 5.003567s
tag_builder 491.178k (± 0.3%) i/s - 2.460M in 5.009140s
Comparison:
content_tag: 561133.8 i/s
tag_builder: 491177.7 i/s - 1.14x (± 0.00) slower
```
Added validation for HTML tag names in the `tag` and `content_tag` helper method. The `tag` and
`content_tag` method now checks that the provided tag name adheres to the HTML specification. If
an invalid HTML tag name is provided, the method raises an `ArgumentError` with an appropriate error
message.
Examples:
```ruby
content_tag("12p") # Starting with a number
content_tag("") # Empty tag name
tag("div/") # Contains a solidus
tag("image file") # Contains a space
```
Register a callable to decode rendered content for a given MIME type
Each registered decoder will also define a `#rendered.$MIME` helper
method, where `$MIME` corresponds to the value of the `mime` argument.
=== Arguments
`mime` - Symbol the MIME Type name for the rendered content
`callable` - Callable to decode the String. Accepts the String
value as its only argument
`block` - Block serves as the decoder when the
`callable` is omitted
By default, ActionView::TestCase defines a decoder for:
* :html - returns an instance of Nokogiri::XML::Node
* :json - returns an instance of ActiveSupport::HashWithIndifferentAccess
Each pre-registered decoder also defines a corresponding helper:
* :html - defines `rendered.html`
* :json - defines `rendered.json`
=== Examples
To parse the rendered content into RSS, register a call to `RSS::Parser.parse`:
```ruby
register_decoder :rss, -> rendered { RSS::Parser.parse(rendered) }
test "renders RSS" do
article = Article.create!(title: "Hello, world")
render formats: :rss, partial: article
assert_equal "Hello, world", rendered.rss.items.last.title
end
```
To parse the rendered content into a Capybara::Simple::Node,
re-register an `:html` decoder with a call to
`Capybara.string`:
```ruby
register_decoder :html, -> rendered { Capybara.string(rendered) }
test "renders HTML" do
article = Article.create!(title: "Hello, world")
render partial: article
rendered.html.assert_css "h1", text: "Hello, world"
end
```
This change would force a lot of existing applications and libraries
to update their tests.
We included it in the beta to collect feedback from the community and
we had some comments about how negative this change would be.
Developers that care about the typography of their error messages
can easily change it in their applications using the translation
files, so there is no need to inflict pain in the upgrade process
by changing the default in the framework.
Revert "Merge PR #45463"
This reverts commit 9f60cd8dc7, reversing
changes made to 35d574dbfd.
Update `include_hidden: false` to `include_hidden: true`
Update the language to be more accurate.
Update actionview/lib/action_view/helpers/form_helper.rb
Co-authored-by: Hartley McGuire <skipkayhil@gmail.com>
Change mentions of `app/views/shared` in the guides to be
`app/views/application` instead. View partials rely on the same
[Template Inheritance][] as their template counterparts, so the guides
should encourage end-users to benefit from that inheritance.
> This makes `app/views/application/` a great place for your shared
> partials, which can then be rendered in your ERB as such:
>
```html+erb
<%# app/views/admin/products/index.html.erb %>
<%= render @products || "empty_list" %>
<%# app/views/application/_empty_list.html.erb %>
There are no items in this list <em>yet</em>.
```
To enforce that template resolution, this commit also replaces
references to `shared/` with `application/` in the Rails test suite.
[Template Inheritance]: https://guides.rubyonrails.org/layouts_and_rendering.html#template-inheritance
Motivation / Background
---
While the `ActionView::TestCase` class isn't marked with a `:nodoc:`
comment to indicate that it's internal to Rails, there isn't much
content in the guides that explains how to test view partials.
Libraries like
[view_component](https://github.com/ViewComponent/view_component/) have
[built-in support for
testing](https://viewcomponent.org/guide/testing.html), including
Capybara integration.
While `ActionView::TestCase` already integrates with
`rails-dom-testing`, that integration could be better documented.
Additionally, it wouldn't take much for consuming applications to mimic
the ViewComponent testing experience for their Action View Partials.
Details
---
First, link to the "Testing Rails Applications" page from the
`ActionView::TestCase` class documentation.
Next, add a "Testing View Partials" section to the guides that expands
upon the variety of tooling available to tests that inherit from
`ActionView::TestCase`. In that section, cover topics like:
* the `render` helper method
* the `rendered` helper attribute reader
* calls to `assert_select` with attribute placeholders
* the `document_root_element` helper method
* integration with Ruby's Pattern Matching
* opportunities to integrate with Capybara
Additional Information
---
Additionally, add test coverage that exercise the examples shared in the
new section, including:
* Calls to `assert_select` that utilize attribute placeholders
* Ruby 3.0's Pattern Matching
* Integration with Capybara
There are assertions that expected/actual arguments are passed in the
reversed order by mistake. Enabling the LiteralAsActualArgument rule
prevents this mistake from happening.
The existing tests were auto-corrected by rubocop with a bit of
indentation adjustment.
Co-authored-by: Jonathan Hefner <jonathan@hefner.pro>
* Add Bun support to `rails new -j` generator
* Add additional generation consideration for Bun
* Use development gems to test the whole workflow
* Remove custom gems from local testing
* Revert lock
* Revert errant custom gem declaration
* Fix linting errors
* Fix remnants of bad merge
* Always use latest bun
* Update actioncable/lib/rails/generators/channel/channel_generator.rb
Co-authored-by: Cadu Ribeiro <mail@cadu.dev>
* Update guides/source/working_with_javascript_in_rails.md
Co-authored-by: Rafael Mendonça França <rafael@franca.dev>
* Only use the latest bun if nothing is specified
* Hardcode known good version
---------
Co-authored-by: Cadu Ribeiro <mail@cadu.dev>
Co-authored-by: Rafael Mendonça França <rafael@franca.dev>
By default `simple_format` method returns the text wrapped with `<p>`. But if we explicitly specify
the `wrapper_tag: nil` in the options, it returns the text wrapped with `<></>` tag.
Before:
```ruby
simple_format("Hello World", {}, { wrapper_tag: nil })
# <>Hello World</>
```
After:
```ruby
simple_format("Hello World", {}, { wrapper_tag: nil })
# <p>Hello World</p>
```
Co-authored-by: Junichi Ito <jit@sonicgarden.jp>
* Document the :ignore_date option on time_select
* split documentation comment into two lines
Co-authored-by: Rafael Mendonça França <rafael@franca.dev>
This commit adds support for composite identifiers in `to_key`.
Rails 7.1 adds support for composite primary key which means that
composite primary key models' `#id` method returns an `Array` and
`to_key` needs to avoid double-wrapping the value.
Before this would raise: `NoMethodError: undefined method `to_key' for nil:NilClass`
After it raises `ArumentError: dom_id must be passed a record_or_class as the first parameter, you passed 'nil'`
Rails 7 ships with Turbo enabled by default. Instead of using
`data-method` and `data-confirm`, Turbo now uses `data-turbo-method` and
`data-turbo-confirm` to perform a link visit with the specified HTTP
method and show confirmation dialog respective.
The deprecated legacy options are documented but the new options are
not.
This commit documents the `data-turbo-method` and `data-turbo-confirm`
for the `link_to` method.
The `button_to` documentation has also been updated to reference the
new `link_to` options.
Followup: https://github.com/rails/rails/pull/48645
Some template engines such as `jbuilder` use these Action View primitives
with types other than strings, which breaks a bunch of assumptions.
I wish I could add a test for this, but this is deep in private methods
I don't see a way to cover this.