diff options
Diffstat (limited to 'guides')
27 files changed, 543 insertions, 113 deletions
diff --git a/guides/assets/images/getting_started/unknown_action_create_for_articles.png b/guides/assets/images/getting_started/unknown_action_create_for_articles.png Binary files differindex ec4758e085..e75b9780cc 100644 --- a/guides/assets/images/getting_started/unknown_action_create_for_articles.png +++ b/guides/assets/images/getting_started/unknown_action_create_for_articles.png diff --git a/guides/rails_guides/generator.rb b/guides/rails_guides/generator.rb index 7d4a15962c..2b2ccfa906 100644 --- a/guides/rails_guides/generator.rb +++ b/guides/rails_guides/generator.rb @@ -43,7 +43,6 @@ module RailsGuides end private - def register_kindle_mime_types Mime::Type.register_alias("application/xml", :opf, %w(opf)) Mime::Type.register_alias("application/xml", :ncx, %w(ncx)) diff --git a/guides/rails_guides/indexer.rb b/guides/rails_guides/indexer.rb index c707464cdf..576ec85b27 100644 --- a/guides/rails_guides/indexer.rb +++ b/guides/rails_guides/indexer.rb @@ -18,7 +18,6 @@ module RailsGuides end private - def process(string, current_level = 3, counters = [1]) s = StringScanner.new(string) diff --git a/guides/rails_guides/markdown.rb b/guides/rails_guides/markdown.rb index 018f49ffd0..d926d233bb 100644 --- a/guides/rails_guides/markdown.rb +++ b/guides/rails_guides/markdown.rb @@ -30,7 +30,6 @@ module RailsGuides end private - def dom_id(nodes) dom_id = dom_id_text(nodes.last.text) diff --git a/guides/rails_guides/markdown/renderer.rb b/guides/rails_guides/markdown/renderer.rb index 7f14c28bbc..4877e806fd 100644 --- a/guides/rails_guides/markdown/renderer.rb +++ b/guides/rails_guides/markdown/renderer.rb @@ -53,7 +53,6 @@ HTML end private - def convert_footnotes(text) text.gsub(/\[<sup>(\d+)\]<\/sup>/i) do %(<sup class="footnote" id="footnote-#{$1}-ref">) + diff --git a/guides/source/2_3_release_notes.md b/guides/source/2_3_release_notes.md index ee9a499953..b46d5ee4db 100644 --- a/guides/source/2_3_release_notes.md +++ b/guides/source/2_3_release_notes.md @@ -415,7 +415,7 @@ select_datetime(DateTime.now, :prompt => ### AssetTag Timestamp Caching -You're likely familiar with Rails' practice of adding timestamps to static asset paths as a "cache buster." This helps ensure that stale copies of things like images and stylesheets don't get served out of the user's browser cache when you change them on the server. You can now modify this behavior with the `cache_asset_timestamps` configuration option for Action View. If you enable the cache, then Rails will calculate the timestamp once when it first serves an asset, and save that value. This means fewer (expensive) file system calls to serve static assets - but it also means that you can't modify any of the assets while the server is running and expect the changes to get picked up by clients. +You're likely familiar with Rails' practice of adding timestamps to static asset paths as a "cache buster". This helps ensure that stale copies of things like images and stylesheets don't get served out of the user's browser cache when you change them on the server. You can now modify this behavior with the `cache_asset_timestamps` configuration option for Action View. If you enable the cache, then Rails will calculate the timestamp once when it first serves an asset, and save that value. This means fewer (expensive) file system calls to serve static assets - but it also means that you can't modify any of the assets while the server is running and expect the changes to get picked up by clients. ### Asset Hosts as Objects diff --git a/guides/source/5_1_release_notes.md b/guides/source/5_1_release_notes.md index e885b1e42e..f870c4c47c 100644 --- a/guides/source/5_1_release_notes.md +++ b/guides/source/5_1_release_notes.md @@ -41,8 +41,8 @@ Major Features [Pull Request](https://github.com/rails/rails/pull/26836) Rails 5.1 allows managing JavaScript dependencies -from NPM via Yarn. This will make it easy to use libraries like React, VueJS -or any other library from NPM world. The Yarn support is integrated with +from npm via Yarn. This will make it easy to use libraries like React, VueJS +or any other library from npm world. The Yarn support is integrated with the asset pipeline so that all dependencies will work seamlessly with the Rails 5.1 app. diff --git a/guides/source/6_0_release_notes.md b/guides/source/6_0_release_notes.md index cb3ea7737c..c826b19f1a 100644 --- a/guides/source/6_0_release_notes.md +++ b/guides/source/6_0_release_notes.md @@ -178,7 +178,7 @@ Please refer to the [Changelog][action-cable] for detailed changes. `ActionCable::Connection`. ([Pull Request](https://github.com/rails/rails/pull/34194)) -* Convert the Action Cable Javascript package from CoffeeScript to ES2015 and +* Convert the Action Cable JavaScript package from CoffeeScript to ES2015 and publish the source code in the npm distribution. ([Pull Request](https://github.com/rails/rails/pull/34370)) @@ -202,7 +202,7 @@ Please refer to the [Changelog][action-pack] for detailed changes. * Remove deprecated methods in `ActionDispatch::TestResponse`: `#success?` in favor of `#successful?`, `#missing?` in favor of `#not_found?`, - `#error?` in favor of `#server_error?` + `#error?` in favor of `#server_error?`. ([Commit](https://github.com/rails/rails/commit/13ddc92e079e59a0b894e31bf5bb4fdecbd235d1)) ### Deprecations @@ -215,6 +215,10 @@ Please refer to the [Changelog][action-pack] for detailed changes. ### Notable changes +* Change `ActionDispatch::Response#content_type` returning Content-Type + header as it is. + ([Pull Request](https://github.com/rails/rails/pull/36034)) + * Raise an `ArgumentError` if a resource param contains a colon. ([Pull Request](https://github.com/rails/rails/pull/35236)) @@ -229,7 +233,7 @@ Please refer to the [Changelog][action-pack] for detailed changes. * Allow the use of `parsed_body` in `ActionController::TestCase`. ([Pull Request](https://github.com/rails/rails/pull/34717)) -* Raise an `ArgumentError` when multiple root routes exists in the same context +* Raise an `ArgumentError` when multiple root routes exist in the same context without `as:` naming specifications. ([Pull Request](https://github.com/rails/rails/pull/34494)) @@ -245,7 +249,7 @@ Please refer to the [Changelog][action-pack] for detailed changes. * Expose `ActionController::Parameters#each_key`. ([Pull Request](https://github.com/rails/rails/pull/33758)) -* Add purpose metadata to signed/encrypted cookies to prevent copying the value of +* Add purpose and expiry metadata inside signed/encrypted cookies to prevent copying the value of cookies into one another. ([Pull Request](https://github.com/rails/rails/pull/32937)) @@ -298,14 +302,14 @@ Please refer to the [Changelog][action-view] for detailed changes. ### Notable changes -* Clear ActionView cache in development only on file changes, speeding up +* Clear Action View cache in development only on file changes, speeding up development mode. ([Pull Request](https://github.com/rails/rails/pull/35629)) * Move all of the Rails npm packages into a `@rails` scope. ([Pull Request](https://github.com/rails/rails/pull/34905)) -* Only accept formats from registered Mime types. +* Only accept formats from registered MIME types. ([Pull Request](https://github.com/rails/rails/pull/35604), [Pull Request](https://github.com/rails/rails/pull/35753)) * Add allocations to the template and partial rendering server output. @@ -323,7 +327,7 @@ Please refer to the [Changelog][action-view] for detailed changes. enable `ActionView::Template` finalizers. ([Pull Request](https://github.com/rails/rails/pull/32418)) -* Extract the JS `confirm` call to its own, overridable method in `rails_ujs`. +* Extract the JavaScript `confirm` call to its own, overridable method in `rails_ujs`. ([Pull Request](https://github.com/rails/rails/pull/32404)) * Add a `action_controller.default_enforce_utf8` configuration option to handle @@ -402,7 +406,7 @@ Please refer to the [Changelog][active-record] for detailed changes. * Remove support for passing the column name to `count` when a block is passed. ([Commit](https://github.com/rails/rails/commit/67356f2034ab41305af7218f7c8b2fee2d614129)) -* Remove support for delegation of missing methods in a relation to arel. +* Remove support for delegation of missing methods in a relation to Arel. ([Commit](https://github.com/rails/rails/commit/d97980a16d76ad190042b4d8578109714e9c53d0)) * Remove support for delegating missing methods in a relation to private methods of the class. @@ -445,7 +449,7 @@ Please refer to the [Changelog][active-record] for detailed changes. ### Notable changes -* Bump the minimum sqlite3 version to 1.4. +* Bump the minimum version of the `sqlite3` gem to 1.4. ([Pull Request](https://github.com/rails/rails/pull/35844)) * Add `rails db:prepare` to create a database if it doesn't exist, and run its migrations. @@ -577,7 +581,7 @@ Please refer to the [Changelog][active-record] for detailed changes. * Allow the `:to_table` option of `remove_foreign_key` to be invertible. ([Pull Request](https://github.com/rails/rails/pull/33530)) -* Fix default value for mysql time types with specified precision. +* Fix default value for MySQL time types with specified precision. ([Pull Request](https://github.com/rails/rails/pull/33280)) * Fix the `touch` option to behave consistently with `Persistence#touch` method. @@ -682,7 +686,7 @@ Please refer to the [Changelog][active-storage] for detailed changes. * Use the `image_processing` gem for Active Storage variants. This replaces using `mini_magick` directly. - ([Pull Request](https://github.com/rails/rails/pull/32471) + ([Pull Request](https://github.com/rails/rails/pull/32471)) * Replace existing images instead of adding to them when updating an attached model via `update` or `update!` with, say, `@user.update!(images: [ … ])`. @@ -762,7 +766,7 @@ Please refer to the [Changelog][active-support] for detailed changes. ([Pull Request](https://github.com/rails/rails/pull/34123)) * Deprecate `ActiveSupport::Multibyte::Unicode#normalize` - and `ActiveSuppport::Multibyte::Chars#normalize` in favor of + and `ActiveSupport::Multibyte::Chars#normalize` in favor of `String#unicode_normalize`. ([Pull Request](https://github.com/rails/rails/pull/34202)) @@ -771,7 +775,7 @@ Please refer to the [Changelog][active-support] for detailed changes. ([Pull Request](https://github.com/rails/rails/pull/34215)) * Deprecate `ActiveSupport::Multibyte::Unicode#pack_graphemes(array)` - and `ActiveSuppport::Multibyte::Unicode#unpack_graphemes(string)` + and `ActiveSupport::Multibyte::Unicode#unpack_graphemes(string)` in favor of `array.flatten.pack("U*")` and `string.scan(/\X/).map(&:codepoints)`, respectively. ([Pull Request](https://github.com/rails/rails/pull/34254)) diff --git a/guides/source/action_text_overview.md b/guides/source/action_text_overview.md index 07919775e2..a735ec2b0e 100644 --- a/guides/source/action_text_overview.md +++ b/guides/source/action_text_overview.md @@ -46,6 +46,8 @@ happens after every keystroke, and avoids the need to use execCommand at all. ## Installation Run `rails action_text:install` to add the Yarn package and copy over the necessary migration. +Also, you need to set up Active Storage for embedded images and other attachments. +Please refer to the [Active Storage Overview](active_storage_overview.html) guide. ## Examples diff --git a/guides/source/active_record_migrations.md b/guides/source/active_record_migrations.md index 270e4a3bf9..9398244ccf 100644 --- a/guides/source/active_record_migrations.md +++ b/guides/source/active_record_migrations.md @@ -225,6 +225,8 @@ class CreateProducts < ActiveRecord::Migration[5.0] create_table :products do |t| t.string :name t.string :part_number + + t.timestamps end end end diff --git a/guides/source/active_record_multiple_databases.md b/guides/source/active_record_multiple_databases.md new file mode 100644 index 0000000000..d7d9bd1ca9 --- /dev/null +++ b/guides/source/active_record_multiple_databases.md @@ -0,0 +1,288 @@ +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** + +Multiple Databases with Active Record +===================================== + +This guide covers using multiple databases with your Rails application. + +After reading this guide you will know: + +* How to setup your application for multiple databases. +* How automatic connection switching works. +* What features are supported and what's still a work in progress. + +-------------------------------------------------------------------------------- + +As an application grows in popularity and usage you'll need to scale the application +to support your new users and their data. One way in which your application may need +to scale is on the database level. Rails now has support for multiple databases +so you don't have to store your data all in one place. + +At this time the following features are supported: + +* Multiple primary databases and a replica for each +* Automatic connection switching for the model you're working with +* Automatic swapping between the primary and replica depending on the HTTP verb +and recent writes +* Rails tasks for creating, dropping, migrating, and interacting with the multiple +databases + +The following features are not (yet) supported: + +* Sharding +* Joining across clusters +* Load balancing replicas +* Dumping schema caches for multiple databases + +## Setting up your application + +While Rails tries to do most of the work for you there are still some steps you'll +need to do to get your application ready for multiple databases. + +Let's say we have an application with a single primary database and we need to add a +new database for some new tables we're adding. The name of the new database will be +"animals". + +The database.yml looks like this: + +```yaml +production: + database: my_primary_database + user: root + adapter: mysql +``` + +Let's add a replica for the primary, a new writer called animals and a replica for that +as well. To do this we need to change our database.yml from a 2-tier to a 3-tier config. + +```yaml +production: + primary: + database: my_primary_database + user: root + adapter: mysql + primary_replica: + database: my_primary_database + user: root_readonly + adapter: mysql + replica: true + animals: + database: my_animals_database + user: animals_root + adapter: mysql + migrations_paths: db/animals_migrate + animals_replica: + database: my_animals_database + user: animals_readonly + adapter: mysql + replica: true +``` + +When using multiple databases there are a few important settings. + +First, the database name for the primary and replica should be the same because they contain +the same data. Second, the username for the primary and replica should be different, and the +replica user's permissions should be to read and not write. + +When using a replica database you need to add a `replica: true` entry to the replica in the +`database.yml`. This is because Rails otherwise has no way of knowing which one is a replica +and which one is the primary. + +Lastly, for new primary databases you need to set the `migrations_paths` to the directory +where you will store migrations for that database. We'll look more at `migrations_paths` +later on in this guide. + +Now that we have a new database, let's set up the model. In order to use the new database we +need to create a new abstract class and connect to the animals databases. + +```ruby +class AnimalsBase < ApplicationRecord + self.abstract_class = true + + connects_to database: { writing: :animals, reading: :animals_replica } +end +``` + Then we need to +update `ApplicationRecord` to be aware of our new replica. + +```ruby +class ApplicationRecord < ActiveRecord::Base + self.abstract_class = true + + connects_to database: { writing: :primary, reading: :primary_replica } +end +``` + +By default Rails expects the database roles to be `writing` and `reading` for the primary +and replica respectively. If you have a legacy system you may already have roles set up that +you don't want to change. In that case you can set a new role name in your application config. + +```ruby +config.active_record.writing_role = :default +config.active_record.reading_role = :readonly +``` + +It's important to connect to your database in a single model and then inherit from that model +for the tables rather than connect multiple individual models to the same database. Database +clients have a limit to the number of open connections there can be and if you do this it will +multiply the number of connections you have since Rails uses the model class name for the +connection specification name. + +Now that we have the database.yml and the new model set up it's time to create the databases. +Rails 6.0 ships with all the rails tasks you need to use multiple databases in Rails. + +You can run `rails -T` to see all the commands you're able to run. You should see the following: + +``` +$ rails -T +rails db:create # Creates the database from DATABASE_URL or config/database.yml for the ... +rails db:create:animals # Create animals database for current environment +rails db:create:primary # Create primary database for current environment +rails db:drop # Drops the database from DATABASE_URL or config/database.yml for the cu... +rails db:drop:animals # Drop animals database for current environment +rails db:drop:primary # Drop primary database for current environment +rails db:migrate # Migrate the database (options: VERSION=x, VERBOSE=false, SCOPE=blog) +rails db:migrate:animals # Migrate animals database for current environment +rails db:migrate:primary # Migrate primary database for current environment +rails db:migrate:status # Display status of migrations +rails db:migrate:status:animals # Display status of migrations for animals database +rails db:migrate:status:primary # Display status of migrations for primary database +``` + +Running a command like `rails db:create` will create both the primary and animals databases. +Note that there is no command for creating the users and you'll need to do that manually +to support the readonly users for your replicas. If you want to create just the animals +database you can run `rails db:create:animals`. + +## Migrations + +Migrations for multiple databases should live in their own folders prefixed with the +name of the database key in the configuration. + +You also need to set the `migrations_paths` in the database configurations to tell Rails +where to find the migrations. + +For example the `animals` database would look in the `db/animals_migrate` directory and +`primary` would look in `db/migrate`. Rails generators now take a `--database` option +so that the file is generated in the correct directory. The command can be run like so: + +``` +$ rails g migration CreateDogs name:string --database animals +``` + +## Activating automatic connection switching + +Finally, in order to use the read-only replica in your application you'll need to activate +the middleware for automatic switching. + +Automatic switching allows the application to switch from the primary to replica or replica +to primary based on the HTTP verb and whether there was a recent write. + +If the application is receiving a POST, PUT, DELETE, or PATCH request the application will +automatically write to the primary. For the specified time after the write the application +will read from the replica. For a GET or HEAD request the application will read from the +replica unless there was a recent write. + +To activate the automatic connection switching middleware, add or uncomment the following +lines in your application config. + +```ruby +config.active_record.database_selector = { delay: 2.seconds } +config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver +config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session +``` + +Rails guarantees "read your own write" and will send your GET or HEAD request to the +primary if it's within the `delay` window. By default the delay is set to 2 seconds. You +should change this based on your database infrastructure. Rails doesn't guarantee "read +a recent write" for other users within the delay window and will send GET and HEAD requests +to the replicas unless they wrote recently. + +The automatic connection switching in Rails is relatively primitive and deliberately doesn't +do a whole lot. The goal was a system that demonstrated how to do automatic connection +switching that was flexible enough to be customizable by app developers. + +The setup in Rails allows you to easily change how the switching is done and what +parameters it's based on. Let's say you want to use a cookie instead of a session to +decide when to swap connections. You can write your own class: + +```ruby +class MyCookieResolver + # code for your cookie class +end +``` + +And then pass it to the middleware: + +```ruby +config.active_record.database_selector = { delay: 2.seconds } +config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver +config.active_record.database_resolver_context = MyCookieResolver +``` + +## Using manual connection switching + +There are some cases where you may want your application to connect to a primary or a replica +and the automatic connection switching isn't adequate. For example, you may know that for a +particular request you always want to send the request to a replica, even when you are in a +POST request path. + +To do this Rails provides a `connected_to` method that will switch to the connection you +need. + +```ruby +ActiveRecord::Base.connected_to(role: :reading) do + # all code in this block will be connected to the reading role +end +``` + +The "role" in the `connected_to` call looks up the connections that are connected on that +connection handler (or role). The `reading` connection handler will hold all the connections +that were connected via `connects_to` with the role name of `reading`. + +There also may be a case where you have a database that you don't always want to connect to +on application boot but may need for a slow query or analytics. After defining that database +in the database.yml you can connect by passing a database argument to `connected_to` + +```ruby +ActiveRecord::Base.connected_to(database: { reading_slow: :animals_slow_replica }) do + # do something while connected to the slow replica +end +``` + +The `database` argument for `connected_to` will take a symbol or a config hash. + +Note that `connected_to` with a role will look up an existing connection and switch +using the connection specification name. This means that if you pass an unknown role +like `connected_to(role: :nonexistent)` you will get an error that says +`ActiveRecord::ConnectionNotEstablished (No connection pool with 'AnimalsBase' found +for the 'nonexistent' role.)` + +## Caveats + +### Sharding + +As noted at the top, Rails doesn't (yet) support sharding. We had to do a lot of work +to support multiple databases for Rails 6.0. The lack of support for sharding isn't +an oversight, but does require additional work that didn't make it in for 6.0. For now +if you need sharding it may be advisable to continue using one of the many gems +that supports this. + +### Load Balancing Replicas + +Rails also doesn't support automatic load balancing of replicas. This is very +dependent on your infrastructure. We may implement basic, primitive load balancing +in the future, but for an application at scale this should be something your application +handles outside of Rails. + +### Joining Across Databases + +Applications cannot join across databases. Rails 6.1 will support using `has_many` +relationships and creating 2 queries instead of joining, but Rails 6.0 will require +you to split the joins into 2 selects manually. + +### Schema Cache + +If you use a schema cache and multiple databases you'll need to write an initializer +that loads the schema cache from your app. This wasn't an issue we could resolve in +time for Rails 6.0 but hope to have it in a future version soon. diff --git a/guides/source/active_record_querying.md b/guides/source/active_record_querying.md index e40f16e62d..5fb030fad4 100644 --- a/guides/source/active_record_querying.md +++ b/guides/source/active_record_querying.md @@ -1821,6 +1821,21 @@ Client.limit(1).pluck(:name) # => ["David"] ``` +NOTE: You should also know that using `pluck` will trigger eager loading if the relation object contains include values, even if the eager loading is not necessary for the query. For example: + +```ruby +# store association for reusing it +assoc = Company.includes(:account) +assoc.pluck(:id) +# SELECT "companies"."id" FROM "companies" LEFT OUTER JOIN "accounts" ON "accounts"."id" = "companies"."account_id" +``` + +One way to avoid this is to `unscope` the includes: + +```ruby +assoc.unscope(:includes).pluck(:id) +``` + ### `ids` `ids` can be used to pluck all the IDs for the relation using the table's primary key. diff --git a/guides/source/active_storage_overview.md b/guides/source/active_storage_overview.md index 615f576797..932a5dc2e9 100644 --- a/guides/source/active_storage_overview.md +++ b/guides/source/active_storage_overview.md @@ -41,6 +41,8 @@ application (or upgrading your application to Rails 5.2), run `rails active_storage:install` to generate a migration that creates these tables. Use `rails db:migrate` to run the migration. +WARNING: `active_storage_attachments` is a polymorphic join table that stores your model's class name. If your model's class name changes, you will need to run a migration on this table to update the underlying `record_type` to your model's new class name. + Declare Active Storage services in `config/storage.yml`. For each service your application uses, provide a name and the requisite configuration. The example below declares three services named `local`, `test`, and `amazon`: @@ -189,14 +191,21 @@ gem "google-cloud-storage", "~> 1.11", require: false ### Mirror Service -You can keep multiple services in sync by defining a mirror service. When a file -is uploaded or deleted, it's done across all the mirrored services. Mirrored -services can be used to facilitate a migration between services in production. -You can start mirroring to the new service, copy existing files from the old -service to the new, then go all-in on the new service. Define each of the -services you'd like to use as described above and reference them from a mirrored +You can keep multiple services in sync by defining a mirror service. A mirror +service replicates uploads and deletes across two or more subordinate services. + +A mirror service is intended to be used temporarily during a migration between +services in production. You can start mirroring to a new service, copy +pre-existing files from the old service to the new, then go all-in on the new service. +NOTE: Mirroring is not atomic. It is possible for an upload to succeed on the +primary service and fail on any of the subordinate services. Before going +all-in on a new service, verify that all files have been copied. + +Define each of the services you'd like to mirror as described above. Reference +them by name when defining a mirror service: + ```yaml s3_west_coast: service: S3 @@ -219,9 +228,12 @@ production: - s3_west_coast ``` -NOTE: Files are served from the primary service. +Although all secondary services receive uploads, downloads are always handled +by the primary service. -NOTE: This is not compatible with the [direct uploads](#direct-uploads) feature. +Mirror services are compatible with direct uploads. New files are directly +uploaded to the primary service. When a directly-uploaded file is attached to a +record, a background job is enqueued to copy it to the secondary services. Attaching Files to Records -------------------------- diff --git a/guides/source/active_support_core_extensions.md b/guides/source/active_support_core_extensions.md index 1a057832d4..8cb49ca6ae 100644 --- a/guides/source/active_support_core_extensions.md +++ b/guides/source/active_support_core_extensions.md @@ -2633,14 +2633,12 @@ The method `stringify_keys` returns a hash that has a stringified version of the # => {"" => nil, "1" => 1, "a" => :a} ``` -In case of key collision, one of the values will be chosen. The chosen value may not always be the same given the same hash: +In case of key collision, the value will be the one most recently inserted into the hash: ```ruby {"a" => 1, a: 2}.stringify_keys -# The result could either be +# The result will be # => {"a"=>2} -# or -# => {"a"=>1} ``` This method may be useful for example to easily accept both symbols and strings as options. For instance `ActionView::Helpers::FormHelper` defines: @@ -2677,14 +2675,12 @@ The method `symbolize_keys` returns a hash that has a symbolized version of the WARNING. Note in the previous example only one key was symbolized. -In case of key collision, one of the values will be chosen. The chosen value may not always be the same given the same hash: +In case of key collision, the value will be the one most recently inserted into the hash: ```ruby {"a" => 1, a: 2}.symbolize_keys -# The result could either be +# The result will be # => {:a=>2} -# or -# => {:a=>1} ``` This method may be useful for example to easily accept both symbols and strings as options. For instance `ActionController::UrlRewriter` defines @@ -3420,56 +3416,56 @@ NOTE: Defined in `active_support/core_ext/date_and_time/calculations.rb`. #### `prev_day`, `next_day` -In Ruby 1.9 `prev_day` and `next_day` return the date in the last or next day: +`prev_day` and `next_day` return the time in the last or next day: ```ruby -d = Date.new(2010, 5, 8) # => Sat, 08 May 2010 -d.prev_day # => Fri, 07 May 2010 -d.next_day # => Sun, 09 May 2010 +t = Time.new(2010, 5, 8) # => 2010-05-08 00:00:00 +0900 +t.prev_day # => 2010-05-07 00:00:00 +0900 +t.next_day # => 2010-05-09 00:00:00 +0900 ``` -NOTE: Defined in `active_support/core_ext/date_and_time/calculations.rb`. +NOTE: Defined in `active_support/core_ext/time/calculations.rb`. #### `prev_month`, `next_month` -In Ruby 1.9 `prev_month` and `next_month` return the date with the same day in the last or next month: +`prev_month` and `next_month` return the time with the same day in the last or next month: ```ruby -d = Date.new(2010, 5, 8) # => Sat, 08 May 2010 -d.prev_month # => Thu, 08 Apr 2010 -d.next_month # => Tue, 08 Jun 2010 +t = Time.new(2010, 5, 8) # => 2010-05-08 00:00:00 +0900 +t.prev_month # => 2010-04-08 00:00:00 +0900 +t.next_month # => 2010-06-08 00:00:00 +0900 ``` If such a day does not exist, the last day of the corresponding month is returned: ```ruby -Date.new(2000, 5, 31).prev_month # => Sun, 30 Apr 2000 -Date.new(2000, 3, 31).prev_month # => Tue, 29 Feb 2000 -Date.new(2000, 5, 31).next_month # => Fri, 30 Jun 2000 -Date.new(2000, 1, 31).next_month # => Tue, 29 Feb 2000 +Time.new(2000, 5, 31).prev_month # => 2000-04-30 00:00:00 +0900 +Time.new(2000, 3, 31).prev_month # => 2000-02-29 00:00:00 +0900 +Time.new(2000, 5, 31).next_month # => 2000-06-30 00:00:00 +0900 +Time.new(2000, 1, 31).next_month # => 2000-02-29 00:00:00 +0900 ``` -NOTE: Defined in `active_support/core_ext/date_and_time/calculations.rb`. +NOTE: Defined in `active_support/core_ext/time/calculations.rb`. #### `prev_year`, `next_year` -In Ruby 1.9 `prev_year` and `next_year` return a date with the same day/month in the last or next year: +`prev_year` and `next_year` return a time with the same day/month in the last or next year: ```ruby -d = Date.new(2010, 5, 8) # => Sat, 08 May 2010 -d.prev_year # => Fri, 08 May 2009 -d.next_year # => Sun, 08 May 2011 +t = Time.new(2010, 5, 8) # => 2010-05-08 00:00:00 +0900 +t.prev_year # => 2009-05-08 00:00:00 +0900 +t.next_year # => 2011-05-08 00:00:00 +0900 ``` If date is the 29th of February of a leap year, you obtain the 28th: ```ruby -d = Date.new(2000, 2, 29) # => Tue, 29 Feb 2000 -d.prev_year # => Sun, 28 Feb 1999 -d.next_year # => Wed, 28 Feb 2001 +t = Time.new(2000, 2, 29) # => 2000-02-29 00:00:00 +0900 +t.prev_year # => 1999-02-28 00:00:00 +0900 +t.next_year # => 2001-02-28 00:00:00 +0900 ``` -NOTE: Defined in `active_support/core_ext/date_and_time/calculations.rb`. +NOTE: Defined in `active_support/core_ext/time/calculations.rb`. #### `prev_quarter`, `next_quarter` diff --git a/guides/source/active_support_instrumentation.md b/guides/source/active_support_instrumentation.md index 4868b00bbe..9f15e70da6 100644 --- a/guides/source/active_support_instrumentation.md +++ b/guides/source/active_support_instrumentation.md @@ -643,7 +643,16 @@ The block receives the following arguments: ```ruby ActiveSupport::Notifications.subscribe "process_action.action_controller" do |name, started, finished, unique_id, data| # your own custom stuff - Rails.logger.info "#{name} Received!" + Rails.logger.info "#{name} Received! (started: #{started}, finished: #{finished})" # process_action.action_controller Received (started: 2019-05-05 13:43:57 -0800, finished: 2019-05-05 13:43:58 -0800) +end +``` + +If you are concerned about the accuracy of `started` and `finished` to compute a precise elapsed time then use `ActiveSupport::Notifications.monotonic_subscribe`. The given block would receive the same arguments as above but the `started` and `finished` will have values with an accurate monotonic time instead of wall-clock time. + +```ruby +ActiveSupport::Notifications.monotonic_subscribe "process_action.action_controller" do |name, started, finished, unique_id, data| + # your own custom stuff + Rails.logger.info "#{name} Received! (started: #{started}, finished: #{finished})" # process_action.action_controller Received (started: 1560978.425334, finished: 1560979.429234) end ``` diff --git a/guides/source/association_basics.md b/guides/source/association_basics.md index 62e9270539..27387ac3ac 100644 --- a/guides/source/association_basics.md +++ b/guides/source/association_basics.md @@ -2451,8 +2451,8 @@ Extensions can refer to the internals of the association proxy using these three * `proxy_association.reflection` returns the reflection object that describes the association. * `proxy_association.target` returns the associated object for `belongs_to` or `has_one`, or the collection of associated objects for `has_many` or `has_and_belongs_to_many`. -Single Table Inheritance ------------------------- +Single Table Inheritance (STI) +------------------------------ Sometimes, you may want to share fields and behavior between different models. Let's say we have Car, Motorcycle, and Bicycle models. We will want to share diff --git a/guides/source/command_line.md b/guides/source/command_line.md index 55f8c84b66..4681574edd 100644 --- a/guides/source/command_line.md +++ b/guides/source/command_line.md @@ -92,6 +92,28 @@ $ rails new commandsapp Rails will set you up with what seems like a huge amount of stuff for such a tiny command! You've got the entire Rails directory structure now with all the code you need to run our simple application right out of the box. +If you wish to skip some files or components from being generated, you can append the following arguments to your `rails new` command: + +| Argument | Description | +| ----------------------- | ----------------------------------------------------------- | +| `--skip-gemfile` | Don't create a Gemfile | +| `--skip-git` | Skip .gitignore file | +| `--skip-keeps` | Skip source control .keep files | +| `--skip-action-mailer` | Skip Action Mailer files | +| `--skip-action-text` | Skip Action Text gem | +| `--skip-active-record` | Skip Active Record files | +| `--skip-active-storage` | Skip Active Storage files | +| `--skip-puma` | Skip Puma related files | +| `--skip-action-cable` | Skip Action Cable files | +| `--skip-sprockets` | Skip Sprockets files | +| `--skip-spring` | Don't install Spring application preloader | +| `--skip-listen` | Don't generate configuration that depends on the listen gem | +| `--skip-javascript` | Skip JavaScript files | +| `--skip-turbolinks` | Skip turbolinks gem | +| `--skip-test` | Skip test files | +| `--skip-system-test` | Skip system test files | +| `--skip-bootsnap` | Skip bootsnap gem | + ### `rails server` The `rails server` command launches a web server named Puma which comes bundled with Rails. You'll use this any time you want to access your application through a web browser. diff --git a/guides/source/configuring.md b/guides/source/configuring.md index 3adc956ef9..ffff9417b9 100644 --- a/guides/source/configuring.md +++ b/guides/source/configuring.md @@ -69,7 +69,7 @@ These configuration methods are to be called on a `Rails::Railtie` object, such * `config.cache_classes` controls whether or not application classes and modules should be reloaded on each request. Defaults to `false` in development mode, and `true` in test and production modes. * `config.beginning_of_week` sets the default beginning of week for the -application. Accepts a valid week day symbol (e.g. `:monday`). +application. Accepts a valid day of week as a symbol (e.g. `:monday`). * `config.cache_store` configures which cache store to use for Rails caching. Options include one of the symbols `:memory_store`, `:file_store`, `:mem_cache_store`, `:null_store`, `:redis_cache_store`, or an object that implements the cache API. Defaults to `:file_store`. @@ -157,6 +157,13 @@ defaults to `:debug` for all environments. The available log levels are: `:debug * `config.time_zone` sets the default time zone for the application and enables time zone awareness for Active Record. +* `config.autoloader` sets the autoloading mode. This option defaults to `:zeitwerk` if `6.0` is specified in `config.load_defaults`. Applications can still use the classic autoloader by setting this value to `:classic` after loading the framework defaults: + + ```ruby + config.load_defaults "6.0" + config.autoloader = :classic + ``` + ### Configuring Assets * `config.assets.enabled` a flag that controls whether the asset @@ -383,6 +390,12 @@ All these configuration options are delegated to the `I18n` library. having to send a query to the database to get this information. Defaults to `true`. +* `config.active_record.collection_cache_versioning` enables the same cache key + to be reused when the object being cached of type `ActiveRecord::Relation` + changes by moving the volatile information (max updated at and count) of + the relation's cache key into the cache version to support recycling cache key. + Defaults to `false`. + The MySQL adapter adds one additional configuration option: * `ActiveRecord::ConnectionAdapters::Mysql2Adapter.emulate_booleans` controls whether Active Record will consider all `tinyint(1)` columns as booleans. Defaults to `true`. @@ -540,6 +553,10 @@ Defaults to `'signed cookie'`. Any exceptions that are not configured will be mapped to 500 Internal Server Error. +* `config.action_dispatch.return_only_media_type_on_content_type` change the + return value of `ActionDispatch::Response#content_type` to the Content-Type + header without modification. Defaults to `false`. + * `ActionDispatch::Callbacks.before` takes a block of code to run before the request. * `ActionDispatch::Callbacks.after` takes a block of code to run after the request. @@ -822,10 +839,10 @@ You can find more detailed configuration options in the config.active_storage.paths[:ffprobe] = '/usr/local/bin/ffprobe' ``` -* `config.active_storage.variable_content_types` accepts an array of strings indicating the content types that Active Storage can transform through ImageMagick. The default is `%w(image/png image/gif image/jpg image/jpeg image/pjpeg image/tiff image/vnd.adobe.photoshop image/vnd.microsoft.icon)`. +* `config.active_storage.variable_content_types` accepts an array of strings indicating the content types that Active Storage can transform through ImageMagick. The default is `%w(image/png image/gif image/jpg image/jpeg image/pjpeg image/tiff image/bmp image/vnd.adobe.photoshop image/vnd.microsoft.icon)`. * `config.active_storage.content_types_to_serve_as_binary` accepts an array of strings indicating the content types that Active Storage will always serve as an attachment, rather than inline. The default is `%w(text/html -text/javascript image/svg+xml application/postscript application/x-shockwave-flash text/xml application/xml application/xhtml+xml)`. +text/javascript image/svg+xml application/postscript application/x-shockwave-flash text/xml application/xml application/xhtml+xml application/mathml+xml text/cache-manifest)`. * `config.active_storage.queues.analysis` accepts a symbol indicating the Active Job queue to use for analysis jobs. When this option is `nil`, analysis jobs are sent to the default Active Job queue (see `config.active_job.default_queue_name`). @@ -839,6 +856,12 @@ text/javascript image/svg+xml application/postscript application/x-shockwave-fla config.active_storage.queues.purge = :low_priority ``` +* `config.active_storage.queues.mirror` accepts a symbol indicating the Active Job queue to use for direct upload mirroring jobs. The default is `:active_storage_mirror`. + + ```ruby + config.active_storage.queues.mirror = :low_priority + ``` + * `config.active_storage.logger` can be used to set the logger used by Active Storage. Accepts a logger conforming to the interface of Log4r or the default Ruby Logger class. ```ruby @@ -878,7 +901,7 @@ text/javascript image/svg+xml application/postscript application/x-shockwave-fla #### With '5.2': - `config.active_record.cache_versioning`: `true` -- `action_dispatch.use_authenticated_cookie_encryption`: `true` +- `config.action_dispatch.use_authenticated_cookie_encryption`: `true` - `config.active_support.use_authenticated_message_encryption`: `true` - `config.active_support.use_sha1_digests`: `true` - `config.action_controller.default_protect_from_forgery`: `true` @@ -886,12 +909,15 @@ text/javascript image/svg+xml application/postscript application/x-shockwave-fla #### With '6.0': +- `config.autoloader`: `:zeitwerk` - `config.action_view.default_enforce_utf8`: `false` - `config.action_dispatch.use_cookies_with_metadata`: `true` +- `config.action_dispatch.return_only_media_type_on_content_type`: `false` - `config.action_mailer.delivery_job`: `"ActionMailer::MailDeliveryJob"` - `config.active_job.return_false_on_aborted_enqueue`: `true` - `config.active_storage.queues.analysis`: `:active_storage_analysis` - `config.active_storage.queues.purge`: `:active_storage_purge` +- `config.active_record.collection_cache_versioning`: `true` ### Configuring a Database diff --git a/guides/source/contributing_to_ruby_on_rails.md b/guides/source/contributing_to_ruby_on_rails.md index a6eb9907a0..d3706a4dbf 100644 --- a/guides/source/contributing_to_ruby_on_rails.md +++ b/guides/source/contributing_to_ruby_on_rails.md @@ -13,7 +13,7 @@ After reading this guide, you will know: * How to contribute to the Ruby on Rails documentation. * How to contribute to the Ruby on Rails code. -Ruby on Rails is not "someone else's framework." Over the years, thousands of people have contributed to Ruby on Rails ranging from a single character to massive architectural changes or significant documentation - all with the goal of making Ruby on Rails better for everyone. Even if you don't feel up to writing code or documentation yet, there are a variety of other ways that you can contribute, from reporting issues to testing patches. +Ruby on Rails is not "someone else's framework". Over the years, thousands of people have contributed to Ruby on Rails ranging from a single character to massive architectural changes or significant documentation - all with the goal of making Ruby on Rails better for everyone. Even if you don't feel up to writing code or documentation yet, there are a variety of other ways that you can contribute, from reporting issues to testing patches. As mentioned in [Rails' README](https://github.com/rails/rails/blob/master/README.md), everyone interacting in Rails and its sub-projects' codebases, issue trackers, chat rooms, and mailing lists is expected to follow the Rails [code of conduct](https://rubyonrails.org/conduct/). @@ -76,7 +76,7 @@ a patch, please send an email to the [rails-core mailing list](https://groups.google.com/forum/?fromgroups#!forum/rubyonrails-core). You might get no response, which means that everyone is indifferent. You might find someone who's also interested in building that feature. You might get a "This -won't be accepted." But it's the proper place to discuss new ideas. GitHub +won't be accepted". But it's the proper place to discuss new ideas. GitHub Issues are not a particularly good venue for the sometimes long and involved discussions new features require. diff --git a/guides/source/documents.yaml b/guides/source/documents.yaml index 1e67b2bce7..8df1c601a7 100644 --- a/guides/source/documents.yaml +++ b/guides/source/documents.yaml @@ -160,6 +160,11 @@ work_in_progress: true url: active_record_postgresql.html description: This guide covers PostgreSQL specific usage of Active Record. + - + name: Multiple Databases with Active Record + work_in_progress: true + url: active_record_multiple_databases.html + description: This guide covers using multiple databases in your application. - name: Extending Rails @@ -193,7 +198,7 @@ - name: Contributing to Ruby on Rails url: contributing_to_ruby_on_rails.html - description: Rails is not 'somebody else's framework.' This guide covers a variety of ways that you can get involved in the ongoing development of Rails. + description: Rails is not "someone else's framework". This guide covers a variety of ways that you can get involved in the ongoing development of Rails. - name: API Documentation Guidelines url: api_documentation_guidelines.html diff --git a/guides/source/engines.md b/guides/source/engines.md index 3031c62928..90b08b00f0 100644 --- a/guides/source/engines.md +++ b/guides/source/engines.md @@ -1511,34 +1511,35 @@ These are the hooks you can use in your own code. To hook into the initialization process of one of the following classes use the available hook. -| Class | Available Hooks | -| --------------------------------- | ------------------------------------ | -| `ActionCable` | `action_cable` | -| `ActionCable::Channel::Base` | `action_cable_channel` | -| `ActionCable::Connection::Base` | `action_cable_connection` | -| `ActionController::API` | `action_controller_api` | -| `ActionController::API` | `action_controller` | -| `ActionController::Base` | `action_controller_base` | -| `ActionController::Base` | `action_controller` | -| `ActionController::TestCase` | `action_controller_test_case` | -| `ActionDispatch::IntegrationTest` | `action_dispatch_integration_test` | -| `ActionDispatch::SystemTestCase` | `action_dispatch_system_test_case` | -| `ActionMailbox::Base` | `action_mailbox` | -| `ActionMailbox::InboundEmail` | `action_mailbox_inbound_email` | -| `ActionMailbox::TestCase` | `action_mailbox_test_case` | -| `ActionMailer::Base` | `action_mailer` | -| `ActionMailer::TestCase` | `action_mailer_test_case` | -| `ActionText::Content` | `action_text_content` | -| `ActionText::RichText` | `action_text_rich_text` | -| `ActionView::Base` | `action_view` | -| `ActionView::TestCase` | `action_view_test_case` | -| `ActiveJob::Base` | `active_job` | -| `ActiveJob::TestCase` | `active_job_test_case` | -| `ActiveRecord::Base` | `active_record` | -| `ActiveStorage::Attachment` | `active_storage_attachment` | -| `ActiveStorage::Blob` | `active_storage_blob` | -| `ActiveSupport::TestCase` | `active_support_test_case` | -| `i18n` | `i18n` | +| Class | Available Hooks | +| -------------------------------------| ------------------------------------ | +| `ActionCable` | `action_cable` | +| `ActionCable::Channel::Base` | `action_cable_channel` | +| `ActionCable::Connection::Base` | `action_cable_connection` | +| `ActionCable::Connection::TestCase` | `action_cable_connection_test_case` | +| `ActionController::API` | `action_controller_api` | +| `ActionController::API` | `action_controller` | +| `ActionController::Base` | `action_controller_base` | +| `ActionController::Base` | `action_controller` | +| `ActionController::TestCase` | `action_controller_test_case` | +| `ActionDispatch::IntegrationTest` | `action_dispatch_integration_test` | +| `ActionDispatch::SystemTestCase` | `action_dispatch_system_test_case` | +| `ActionMailbox::Base` | `action_mailbox` | +| `ActionMailbox::InboundEmail` | `action_mailbox_inbound_email` | +| `ActionMailbox::TestCase` | `action_mailbox_test_case` | +| `ActionMailer::Base` | `action_mailer` | +| `ActionMailer::TestCase` | `action_mailer_test_case` | +| `ActionText::Content` | `action_text_content` | +| `ActionText::RichText` | `action_text_rich_text` | +| `ActionView::Base` | `action_view` | +| `ActionView::TestCase` | `action_view_test_case` | +| `ActiveJob::Base` | `active_job` | +| `ActiveJob::TestCase` | `active_job_test_case` | +| `ActiveRecord::Base` | `active_record` | +| `ActiveStorage::Attachment` | `active_storage_attachment` | +| `ActiveStorage::Blob` | `active_storage_blob` | +| `ActiveSupport::TestCase` | `active_support_test_case` | +| `i18n` | `i18n` | ## Configuration hooks diff --git a/guides/source/getting_started.md b/guides/source/getting_started.md index 7000fa408c..64f4a3b6b3 100644 --- a/guides/source/getting_started.md +++ b/guides/source/getting_started.md @@ -55,7 +55,7 @@ The Rails philosophy includes two major guiding principles: * **Don't Repeat Yourself:** DRY is a principle of software development which states that "Every piece of knowledge must have a single, unambiguous, authoritative - representation within a system." By not writing the same information over and over + representation within a system". By not writing the same information over and over again, our code is more maintainable, more extensible, and less buggy. * **Convention Over Configuration:** Rails has opinions about the best way to do many things in a web application, and defaults to this set of conventions, rather than @@ -207,7 +207,7 @@ folder directly to the Ruby interpreter e.g. `ruby bin\rails server`. TIP: JavaScript asset compression requires you have a JavaScript runtime available on your system, in the absence -of a runtime you will see an `execjs` error during asset compilation. +of a runtime you will see an `execjs` error during asset compression. Usually macOS and Windows come with a JavaScript runtime installed. `therubyrhino` is the recommended runtime for JRuby users and is added by default to the `Gemfile` in apps generated under JRuby. You can investigate diff --git a/guides/source/initialization.md b/guides/source/initialization.md index c41eae18cf..c19b2cffc5 100644 --- a/guides/source/initialization.md +++ b/guides/source/initialization.md @@ -160,8 +160,8 @@ namespace and executes the command if found. If Rails doesn't recognize the command, it hands the reins over to Rake to run a task of the same name. -As shown, `Rails::Command` displays the help output automatically if the `args` -are empty. +As shown, `Rails::Command` displays the help output automatically if the `namespace` +is empty. ```ruby module Rails::Command @@ -289,7 +289,7 @@ def default_options environment: (ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development").dup, daemonize: false, caching: nil, - pid: Options::DEFAULT_PID_PATH, + pid: ENV.fetch("PIDFILE", Options::DEFAULT_PIDFILE).dup, restart_cmd: restart_command) end ``` diff --git a/guides/source/routing.md b/guides/source/routing.md index e3a6bbb138..4aeb9ee585 100644 --- a/guides/source/routing.md +++ b/guides/source/routing.md @@ -508,7 +508,7 @@ end This will recognize `/photos/1/preview` with GET, and route to the `preview` action of `PhotosController`, with the resource id value passed in `params[:id]`. It will also create the `preview_photo_url` and `preview_photo_path` helpers. -Within the block of member routes, each route name specifies the HTTP verb +Within the block of member routes, each route name specifies the HTTP verb that will be recognized. You can use `get`, `patch`, `put`, `post`, or `delete` here . If you don't have multiple `member` routes, you can also pass `:on` to a route, eliminating the block: diff --git a/guides/source/security.md b/guides/source/security.md index 22c122d4b9..5bb7a51524 100644 --- a/guides/source/security.md +++ b/guides/source/security.md @@ -1211,4 +1211,4 @@ The security landscape shifts and it is important to keep up to date, because mi * Subscribe to the Rails security [mailing list](https://groups.google.com/forum/#!forum/rubyonrails-security). * [Brakeman - Rails Security Scanner](https://brakemanscanner.org/) - To perform static security analysis for Rails applications. * [Keep up to date on the other application layers](http://secunia.com/) (they have a weekly newsletter, too). -* A [good security blog](https://www.owasp.org) including the [Cross-Site scripting Cheat Sheet](https://www.owasp.org/index.php/DOM_based_XSS_Prevention_Cheat_Sheet). +* A [good security blog](https://www.owasp.org) including the [Cross-Site scripting Cheat Sheet](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.md). diff --git a/guides/source/testing.md b/guides/source/testing.md index 9540bb2af5..41bc54b924 100644 --- a/guides/source/testing.md +++ b/guides/source/testing.md @@ -1144,7 +1144,7 @@ test "ajax request" do get article_url(article), xhr: true assert_equal 'hello world', @response.body - assert_equal "text/javascript", @response.content_type + assert_equal "text/javascript", @response.media_type end ``` diff --git a/guides/source/upgrading_ruby_on_rails.md b/guides/source/upgrading_ruby_on_rails.md index 5bd4b06274..54f014293d 100644 --- a/guides/source/upgrading_ruby_on_rails.md +++ b/guides/source/upgrading_ruby_on_rails.md @@ -85,13 +85,14 @@ Rails 6.1. You are encouraged to enable `config.force_ssl` to enforce HTTPS connections throughout your application. If you need to exempt certain endpoints from redirection, you can use `config.ssl_options` to configure that behavior. -### Purpose in signed or encrypted cookie is now embedded within cookies +### Purpose and expiry metadata is now embedded inside signed and encrypted cookies for increased security + +To improve security, Rails embeds the purpose and expiry metadata inside encrypted or signed cookies value. -To improve security, Rails embeds the purpose information in encrypted or signed cookies value. Rails can then thwart attacks that attempt to copy the signed/encrypted value of a cookie and use it as the value of another cookie. -This new embed information make those cookies incompatible with versions of Rails older than 6.0. +This new embed metadata make those cookies incompatible with versions of Rails older than 6.0. If you require your cookies to be read by Rails 5.2 and older, or you are still validating your 6.0 deploy and want to be able to rollback set @@ -133,6 +134,28 @@ Action Cable JavaScript API: + ActionCable.logger.enabled = false ``` +### `ActionDispatch::Response#content_type` now returns the Content-Type header without modification + +Previously, the return value of `ActionDispatch::Response#content_type` did NOT contain the charset part. +This behavior has changed to include the previously omitted charset part as well. + +If you want just the MIME type, please use `ActionDispatch::Response#media_type` instead. + +Before: + +```ruby +resp = ActionDispatch::Response.new(200, "Content-Type" => "text/csv; header=present; charset=utf-16") +resp.content_type #=> "text/csv; header=present" +``` + +After: + +```ruby +resp = ActionDispatch::Response.new(200, "Content-Type" => "text/csv; header=present; charset=utf-16") +resp.content_type #=> "text/csv; header=present; charset=utf-16" +resp.media_type #=> "text/csv" +``` + ### Autoloading The default configuration for Rails 6 @@ -140,7 +163,7 @@ The default configuration for Rails 6 ```ruby # config/application.rb -load_defaults "6.0" +config.load_defaults "6.0" ``` enables `zeitwerk` autoloading mode on CRuby. In that mode, autoloading, reloading, and eager loading are managed by [Zeitwerk](https://github.com/fxn/zeitwerk). @@ -166,7 +189,7 @@ However, `classic` mode infers file names from missing constant names (`undersco ```ruby # config/application.rb -load_defaults "6.0" +config.load_defaults "6.0" config.autoloader = :classic ``` @@ -187,7 +210,7 @@ In the case of STIs with a hierarchy of more than two levels, you can preload th ```ruby # config/initializers/preload_stis.rb -# By preloading leaves, the entire hierarchy is loaded upwards following +# By preloading leaves, the hierarchy is loaded upwards following # the references to superclasses in the class definitions. sti_leaves = %w( app/models/leaf1.rb @@ -281,6 +304,35 @@ won't work, child objects like `Hotel::Pricing` won't be found. This restriction only applies to explicit namespaces. Classes and modules not defining a namespace can be defined using those idioms. +#### One file, one constant (at the same top-level) + +In `classic` mode you could technically define several constants at the same top-level and have them all reloaded. For example, given + +```ruby +# app/models/foo.rb + +class Foo +end + +class Bar +end +``` + +while `Bar` could not be autoloaded, autoloading `Foo` would mark `Bar` as autoloaded too. This is not the case in `zeitwerk` mode, you need to move `Bar` to its own file `bar.rb`. One file, one constant. + +This affects only to constants at the same top-level as in the example above. Inner classes and modules are fine. For example, consider + +```ruby +# app/models/foo.rb + +class Foo + class InnerClass + end +end +``` + +If the application reloads `Foo`, it will reload `Foo::InnerClass` too. + #### Spring and the `test` Environment Spring reloads the application code if something changes. In the `test` environment you need to enable reloading for that to work: @@ -319,7 +371,7 @@ By opting-out you optimize `$LOAD_PATH` lookups (less directories to check), and #### Thread-safety -In classic mode constant autoloading is not thread-safe, though Rails has locks in place for example to make web requests thread-safe when autoloading is enabled, as it is common in `development` mode. +In classic mode, constant autoloading is not thread-safe, though Rails has locks in place for example to make web requests thread-safe when autoloading is enabled, as it is common in `development` mode. Constant autoloading is thread-safe in `zeitwerk` mode. For example, you can now autoload in multi-threaded scripts executed by the `runner` command. @@ -346,7 +398,7 @@ Applications can load Rails 6 defaults and still use the classic autoloader by s ```ruby # config/application.rb -load_defaults "6.0" +config.load_defaults "6.0" config.autoloader = :classic ``` @@ -1774,7 +1826,7 @@ config.assets.enabled = true config.assets.version = '1.0' ``` -If your application is using an "/assets" route for a resource you may want change the prefix used for assets to avoid conflicts: +If your application is using an "/assets" route for a resource you may want to change the prefix used for assets to avoid conflicts: ```ruby # Defaults to '/assets' |