What is new in Rails 6.0

Hello!
This post about news and some changes that have been done in Rails 6.0.
Table of Contents
- Rails 6.0 requires Ruby 2.5.0 or newer
- Parallel testing
- ActiveRecord::Relation#pick as shorthand for single-value plucks
- ActiveRecord::Relation#create_or_find_by/! to lean on unique constraints
- Action Mailbox
- Action Text
- Action Cable testing
- Other links
Rails 6.0 requires Ruby 2.5.0 or newer
Pull Requests:
Parallel testing
Pull Requests:
- Parallel testing
- Add option to set parallel test worker count to the physical core count of the machine
You know that class ActiveSupport::TestCase
uses minitest under the hood (Minitest::Test
is the superclass of the class).
To ActiveSupport::TestCase
was added parallelize
method.
It allows you to parallelize your test suite with forked processes.
Running tests in parallel reduces the time it takes your entire test suite to run.
Running test in threads is supported as well, but note that it doesn’t make your test run faster (read “Minitest Parallelization and You” since it uses Minitest::Parallel::Executor
).
The default parallelization method is to fork processes using Ruby’s DRb system.
To enable parallelization with forked processes add the following to your test/test_helper.rb
:
class ActiveSupport::TestCase
parallelize(workers: 3, with: :processes)
end
The :workers
option controls how many times the the process is forked or how many threads are used.
The default number of workers is the actual physical core count on the machine you are on:
class ActiveSupport::TestCase
parallelize(workers: :number_of_processors)
end
If you would like to parallelize your test suite with threads, you should set :with
option to :threads
:
class ActiveSupport::TestCase
parallelize(workers: 3, with: :threads)
end
You can also use environment variable PARALLEL_WORKERS
to easily change the number of workers a test run should use.
This is useful for CI environments or other environments where you may need more or less workers than you do for local testing:
PARALLEL_WORKERS=6 bin/rails test
When parallelizing test with processes, Active Record automatically handles creating a database and loading the schema into the database for each process. The databases will be suffixed with the number corresponding to the worker.
For example, if you have 2 workers the tests will create test_database-0
and test_database-1
databases respectively.
If the number of workers passed is 1 or fewer the processes will not be forked and the tests will not be parallelized and the tests will use the original test_database
database.
Also, two hooks are provided, one runs when the process is forked but before the tests run, and one runs before the forked process is closed.
These can be useful if your app uses multiple databases or perform other tasks that depend on the number of workers.
The parallelize_setup
method is called right after the process is forked. The parallelize_teardown
method is called right before the process is closed:
class ActiveSupport::TestCase
parallelize_setup do |worker|
# code
end
parallelize_teardown do |worker|
# code
end
parallelize(workers: 2)
end
Note that these methods are not available with the threaded parallelization.
ActiveRecord::Relation#pick as shorthand for single-value plucks
Pull Requests:
I am sure you know about the method #pluck
that has been in Rails since version 3.2.0.
Let’s refresh our knowledge.
#pluck
is a shortcut to select one or more attributes without loading a bunch of records just to grab the attributes you want:
User.pluck(:name)
# SELECT "users"."name" FROM "users"
# => ["Bogdan", "David"]
User.where(id: 1).pluck(:name, :email)
# SELECT "users"."name", "users"."email" FROM "users" WHERE "users"."id" = ? [["id", 1]]
# => [["Bogdan", "bogdanvlviv@gmail.com"]]
User.where("1=0").pluck(:name)
# SELECT "users"."name" FROM "users" WHERE (1=0)
# => []
But sometimes you just need single value(s) from the result. To get this you can do something like:
User.limit(1).pluck(:name).first
# SELECT "users"."name" FROM "users" LIMIT ? [["LIMIT", 1]]
# => "Bogdan"
User.where(id: 1).limit(1).pluck(:name, :email).first
# SELECT "users"."name", "users"."email" FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
# => ["Bogdan", "bogdanvlviv@gmail.com"]
Since Rails 6.0 you can use the method #pick
, it is shorthand for limit(1).pluck(*column_names).first
:
User.pick(:name)
# SELECT "users"."name" FROM "users" LIMIT ? [["LIMIT", 1]]
# => "Bogdan"
User.where(id: 1).pick(:name, :email)
# SELECT "users"."name", "users"."email" FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
# => ["Bogdan", "bogdanvlviv@gmail.com"]
User.pick(Arel.sql("UPPER(name)"))
# SELECT UPPER(name) FROM "users" LIMIT ? [["LIMIT", 1]]
# => "BOGDAN"
User.where("1=0").pick(:name)
# SELECT "users"."name" FROM "users" WHERE (1=0) LIMIT ? [["LIMIT", 1]]
# => nil
You probably noticed that the method #pluck
does not guarantee the order of the returned value(s) by any column.
So note that #pick
does not guarantee to return the value(s) of the first row ordered by any column either.
For instance, if you want to get value(s) of the first row ordered by id
column, you should apply order(:id)
before pick
:
User.order(:id).pick(:name)
# SELECT "users"."name" FROM "users" ORDER BY "users"."id" ASC LIMIT ? [["LIMIT", 1]]
# => "Bogdan"
ActiveRecord::Relation#create_or_find_by/! to lean on unique constraints
Pull Requests:
- Add #create_or_find_by to lean on unique constraints
- #create_or_find_by/!: add more tests and fix docs
#create_or_find_by
attempts to create a record with the given attributes in a table that has a unique constraint
on one or several of its columns.
If a row already exists with one or several of these unique constraints, the exception such an insertion would normally raise is caught and the existing record with those attributes is found using #find_by!
.
This is similar to #find_or_create_by
, but avoids the problem of stale reads between the SELECT
and the INSERT
, as that method needs to first query the table, then attempt to insert a row if none is found.
There are several drawbacks to #create_or_find_by
, though:
- The underlying table must have the relevant columns defined with unique constraints.
- A unique constraint violation may be triggered by only one, or at least less than all, of the given attributes. This means that the subsequent
#find_by!
may fail to find a matching record, which will then raise anActiveRecord::RecordNotFound
exception, rather than a record with the given attributes. - While we avoid the race condition between
SELECT
->INSERT
from#find_or_create_by
, we actually have another race condition betweenINSERT
->SELECT
, which can be triggered if aDELETE
between those two statements is run by another client. But for most applications, that’s a significantly less likely condition to hit. - It relies on exception handling to handle control flow, which may be marginally slower.
This method will return a record if all given attributes are covered by unique constraints (unless the INSERT
-> DELETE
-> SELECT
race condition is triggered), but if creation was attempted and failed due to validation errors it won’t be persisted, you get what #create
returns in such situation.
#create_or_find_by!
is like #create_or_find_by
, but calls create!
so an exception is raised if the created record is invalid.
Implementation of these methods look like:
def create_or_find_by(attributes, &block)
transaction(requires_new: true) { create(attributes, &block) }
rescue ActiveRecord::RecordNotUnique
find_by!(attributes)
end
def create_or_find_by!(attributes, &block)
transaction(requires_new: true) { create!(attributes, &block) }
rescue ActiveRecord::RecordNotUnique
find_by!(attributes)
end
Examples using of these methods:
User.create_or_find_by(email: "bogdanvlviv@gmail.com") do |user|
user.name = "Bogdan"
end
User.create_or_find_by!(email: "bogdanvlviv@gmail.com") do |user|
user.name = "Богдан"
end
Action Mailbox
Pull Requests:
- Import Action Mailbox
- Add Action Mailbox to guides
- Add
--skip-action-mailbox
option torails new
- Deprecate ActionMailer::Base.receive in favor of Action Mailbox
- Add
rails test:mailboxes
- Add Postmark ingress support to ActionMailbox
- Add Exim and Qmail support to Action Mailbox
Action Mailbox allows you to route incoming emails to controller-like mailboxes. You can read more about Action Mailbox in the Action Mailbox Basics guide.
Action Text
Pull Requests:
Action Text brings rich text content and editing to Rails. It includes the Trix editor that handles everything from formatting to links to quotes to lists to embedded images and galleries. The rich text content generated by the Trix editor is saved in its own RichText model that’s associated with any existing Active Record model in the application. Any embedded images (or other attachments) are automatically stored using Active Storage and associated with the included RichText model.
You can read more about Action Text in the Action Text Overview guide.
Action Cable testing
Pull Requests:
- Action cable testing
- Add ActionCable::Channel::TestCase
- Add streams assert methods to ActionCable channel test case
- Add ActionCable::Connection::TestCase
- Add Action Cable testing guides and generators
- Add
rails test:channels
and fix Action Cable templates
Other links
Start Rails 6.0 development!!!
Introduce custom serializers to ActiveJob arguments
Deprecate update_attributes and update_attributes!
String#strip_heredoc
preserves frozenness`
Add support for timezones to Active Job
Add :private
option to ActiveSupport’s Module#delegate
Don’t enforce UTF-8 by default
Support i18n key at translation of value in submit tag
Add “rails routes –expanded” mode
Enable select tag helper to mark prompt
option as selected
and/or disabled
for required
field
Introduce explicit rails server handler option
Add before?
and after?
methods to date and time classes
Disable ActionView::Template finalizers in test environment
Add AR::Base.base_class? predicate
Deprecate controller level force_ssl
Add #dig to ActionDispatch::Request::Session
Deprecate support for using HOST
environment to specify server IP
Define callbacks on descendants
Introduce ActionDispatch::DebugExceptions interceptors
Add touch_all
method to ActiveRecord::Relation
Part 1 Easy Multi db in Rails: Add basic rake tasks for multi db setup Fix two-level database configurations with URLs Fix structure:dump for multiple databases Allow schema/structure load for multiple databases Add multidb application test Don’t create namespaced tasks if single db application Db schema cache dump and clear multi db Part 5: Multi db improvements, Fix query cache for multiple connections Part 7: Multi db improvements, Add ability to block writes to a database Part 8: Multi db improvements, Adds basic automatic database switching to Rails Add ability to change the names of the default handlers Add ActiveRecord::Base.connected_to?
Use ImageProcessing gem for ActiveStorage variants
Update ‘rails_welcome.png’ to reflect a more diverse population
rails link: Update 'rails_welcome.png' to reflect a more diverse populationhttps://t.co/oyUMkGwuBk pic.twitter.com/LYKTsZ8NK4
— Bogdan (@bogdanvlviv) April 26, 2018
Changes Rails Welcome image on localhost:3000
Loaded associations should not run a new query when size is called
has_(one/many)_attached presence validation
Allow usage of strings as locals for partial renderer
Allow to override the full_message error format
Add year_format
option to date_select tag.
Allow call assert_enqueued_with
and assert_enqueued_email_with
with no block
Allow queue
option to assert_no_enqueued_jobs
Allow configurable attribute name on #has_secure_password
Adds Rails::Command::NotesCommand
and makes rake notes
use it under the hood
Pass along arguments to underlying get
method in follow_redirect!
Store newly-uploaded files on save rather than assignment
rails server: Allow to explicitly specify whether to output Rails’s log to stdout
Add implicit to path conversion to uploaded file
Add a foreign-key constraint to the active_storage_attachments table for blobs
Show nested exceptions on the debug view
Add cpu time, idle time, and allocations features to log subscriber events Add event object subscriptions to AS::Notifications
Add Purpose Metadata to Cookies
33515 invert remove foreign key support “to_table”
Fix AM::Serializers::JSON#as_json method for timestamps
Move dev:cache
rake task to use Rails::Command
Allow perform_enqueued_jobs
to be called without a block.
Improve Active Job test helpers
Deprecate calling private model methods from view helpers.
Add database configuration to disable advisory locks
Omit BEGIN/COMMIT statements for empty transactions
Fail more gracefully from ActiveStorage missing file exceptions
Part 2: Multi-db improvements, Refactor Active Record configurations
Part 3: Multi-db Improvements, identifying replica configurations
Emit warning for unknown inflection rule when generating model.
Make null_store the default cache store in test environment config
Add hooks to ActiveJob around retries and discards
Deprecate most methods which were never used in DatabaseLimits
Maintain html_safe? on sliced HTML safe strings
https://github.com/rails/rails/pull/33798
trace autoloads, and document hints for troubleshooting
update I18n fallbacks configuration to be compatible with i18n 1.1.0
Configuration item config.filter_parameters
could also filter out sensitive values of database columns when call #inspect
.
Implement AR#inspect using ParameterFilter
Add #unfreeze_time to ActiveSupport::Testing::TimeHelpers
Make sure there are no duplicated nested records with create_with
Use utf8mb4 character set by default for MySQL database Bump minimum MySQL version to 5.5.8.
Skip delivery notification when perform_deliveries is false.
TaggedLogging to return a new logger instance
Include test helpers in ActionDispatch::IntegrationTest
Use faster globs for template resolving
Allow subclasses to redefine autosave callbacks for associated records.
SQLite3 adapter supports expression indexes. SQLite3: Support multiple args function for expression indexes
Configure Active Storage route prefix
PostgreSQL: prepare for pg-1.1
Don’t update counter cache unless the record is actually saved
Deprecate ActiveRecord::Result#to_hash in favor of #to_a
Add support for multi environment credentials. Restructure credentials after environment overrides.
Error when using “recyclable” cache keys with a store that does not support it
index option added for change_table migrations
Encode Content-Disposition filenames on send_data and send_file
Fix transaction
reverting for migrations
Add ActionController::Parameters#each_value
Add migrations_paths option to migration generator Add migrations_paths option to model generator Refactor migrations_path command option to database
Add deprecation warning when String#first and String#last receive negative integers
Make Webpacker the default JavaScript compiler for Rails 6
Deprecate the use of LoggerSilence
in favor of ActiveSupport::LoggerSilence
Parameterized mailers can configure delivery job Add MailDeliveryJob for unified mail delivery Move MailDeliveryJob default to 6.0 defaults
Deprecate ActionDispatch::Http::ParameterFilter
in favor of ActiveSupport::ParameterFilter
Add multi-db support to rails db:migrate:status
Fix inconsistent behavior by clearing QueryCache when reloading associations
Enum raises on invalid definition values
Add allocations to template renderer subscription
Part 4: Multi db improvements, Basic API for connection switching Add support for hash and url configs to be used in connected_to
Deprecate ActiveSupport::Multibyte::Unicode#downcase/upcase/swapcase
in favor of String#downcase/upcase/swapcase
Deprecate ActiveSupport::Multibyte::Unicode#normalize
and ActiveSuppport::Multibyte::Chars#normalize
in favor of String#unicode_normalize
Fix duration being rounded to a full second
Use Ids instead of memory addresses when displaying references in scaffold views
Deprecate ActiveSupport::Multibyte::Chars.consumes?
Support default expression and expression indexes for MySQL
ActiveStorage: Don’t include an undefined X-CSRF-Token header when creating a blob record
Make ActiveStorage::Blob keys lowercase
Permit generating variants of TIFF images
Permit sending Active Storage purge and analysis jobs to separate queues Send Active Storage analysis and purge jobs to dedicated queues by default
Fix the need of #protect_against_forgery?
method defined in ActionView::Base
subclasses
Add ActiveModel::Errors#of_kind?
Convert ActionCable javascript to ES2015 modules with a modern build environment
Keep executions for each specific exception
Support in-flight jobs stored before individual execution counters for retry_on
Run exception tests for all ActiveJob adapters and fix issue with individual counters and Resque
Move all npm packages to @rails scope
Add support for endless ranges introduces in Ruby 2.6
Refactor calculating beginning_of_quarter and end_of_quarter
Guard Enums against definitions with blank label names
Add an :if_not_exists option to create_table
Remove asset paths from autoload_paths
Add support for UNLOGGED Postgresql tables
Arel: Implemented DB-aware NULL-safe comparison
Prevent TextHelper#word_wrap from stripping white space on the left side of long lines; Fixes #34487
ActionMailer: support overriding template name in multipart
Add rails db:system:change command
Seed database with inline ActiveJob job adapter
Make t.timestamps
with precision by default
Remove all code deprecated in Rails 5.2
All of queries should return correct result even if including large number
Fix deeply nested namespace command printing
Make t.timestamps
with precision by default
MySQL: Support :size
option to change text and blob size
Action Cable: move channel_name to Channel.broadcasting_for
Support before_reset callback in CurrentAttributes
Improve performance of blank? and present? in an ActiveRecord::Base instance
Move compiled ERB to an AV::Base subclass
Add ‘Hash#deep_transform_values’, and ‘Hash#deep_transform_values!’
Add slice! method to ActiveModel::Errors
Allow all assertion helpers that have a only
and except
keyword to accept Procs
Bump the minimum version of PostgreSQL to 9.3
Make it possible to override the implicit order column
option to disable all scopes that ActiveRecord.enum
generates
Allow using parsed_body in ActionController::TestCase
Introduce guard against DNS rebinding attacks
Add option to set parallel test worker count to the physical core count of the machine
SQLite3: Implement add_foreign_key
and remove_foreign_key
Adding enque time tracking and logging to a job
Add delete_by/destroy_by as relation methods
Ensure update_all
series cares about optimistic locking
Add negative scopes for all enum values
Deprecate mismatched collation comparison for uniqueness validator
Allow truncate
for SQLite3 adapter and add rails db:seed:replant
, rails db:truncate_all
Added Array#including, Array#excluding, Enumerable#including, Enumerable#excluding
Add locale option to #parameterize
Fall back to parent locale before falling back to the :errors namespace
Add -e/--environment
option to rails initializers
Fix Time#advance
to work with dates before 1001-03-07
Add ActiveSupport::Notifications instrumentation of the processing of each middleware in the stack
Add Relation#annotate for SQL commenting
Update `ActiveSupport::Notifications::Instrumenter#instrument to make passing a block optional
Add config.disable_sandbox option to Rails console
Type cast falsy boolean symbols on boolean attribute as false
Add ActiveRecord::Relation#extract_associated
for extracting associated record
Only clear ActionView caches in dev when files change
Add after_save_commit
callback shortcut
Add rails db:prepare
to migrate or setup a database
Use execute_batch2
rather than execute_batch
to fix performance regression for fixture loading