What’s coming to Rails 6.0?

Guy Maliar
Feb 14, 2019 · 7 min read
Image for post
Image for post

Active Record

Add basic API for connection switching to support multiple databases

Connection switching support has been on my list for a long time, I’ve used the Octopus gem a few times before as well, but it always felt a little bit clunky in my opinion.

class AnimalsModel < ApplicationRecord
self.abstract_class = true

connects_to database: { writing: :animals_primary, reading: :animals_replica }
end

class Dog < AnimalsModel
# connected to both the animals_primary db for writing and the animals_replica for reading
end
ActiveRecord::Base.connected_to(database: :slow_replica) do
SlowReplicaModel.first
end
development:
primary:
database: my_primary_db
user: root
primary_replica:
database: my_primary_db
user: ro_user
replica: true
animals:
database: my_animals_db
user: root
animals_replica
database: my_animals_db
user: ro_user
replica: true
User.connected_to(database: { writing: "postgres://foo" }) do
User.create!(name: "Gannon")
end

config = { "adapter" => "sqlite3", "database" => "db/readonly.sqlite3" }
User.connected_to(database: { reading: config }) do
User.count
end

Add Relation#pick as short-hand for single-value plucks

Just as the name suggests pick can pluck single-values

Person.where(id: 1).pick(:name, :email_address)
# SELECT people.name, people.email_address FROM people WHERE id = 1 LIMIT 1
# => ['David', 'david@loudthinking.com']

Add ActiveRecord::Base.create_or_find_by/! to deal with the SELECT/INSERT race condition

A while back, DHH have started YouTube series called On Writing Software Well which later became part of the Getting Better YouTube page, on one of the videos he shows his technique for addressing the issues with find_or_create_by and the alternative create_or_find_by which relies on a database unique constraint. The code itself is fairly intuitive and is taken directly from the Rails sourcecode.

def create_or_find_by(attributes, &block)
transaction(requires_new: true) { create(attributes, &block) }
rescue ActiveRecord::RecordNotUnique
find_by!(attributes)
end

Make the implicit order column configurable

For applications that don’t use sequential IDs this one is golden. When using UUIDs as default column identifier, first and last methods no longer make sense. Now we will be able to set the order of the records with a single line of configuration.

class User < ActiveRecord::Base
self.implicit_order_column = "created_at"
end

Action Mailbox

Action Mailbox is introduced in the sixth version of Ruby on Rails, I’m sure many posts will be written about it in the near future and it’s pretty exciting. Action Mailbox provides a set of tools that will allow applications to better integrate with inbound emails flows.

Example mailbox for adding comments to a Post by email

Action Text

Action Text is an implementation of the new Trix editor by Basecamp bundled into ActiveRecord models. It exposes a has_rich_text method that we can apply to models and Action Text will take care of the rest. Action Text requires ActiveStorage and some database tables to persist it’s metadata, so be aware that you’d want to switch to an ActiveStorage provider that does not persist to disk if you’re working on applications that require more than one server.

Action Pack

Introduce ActionDispatch::HostAuthorization

Host Authorization is a new middleware that guards against DNS rebinding attacks by explicitly permitting the hosts a request can be sent to. More information about the attack itself is available in this Medium post and in Daniel Miessler’s DNS Rebinding attack explained.

Purpose metadata for signed/encrypted cookies

Rails can now thwart attacks that attempt to copy signed/encrypted value of a cookie and use it as the value of another cookie.

Pass along arguments to underlying GET method in #follow_redirect!

It’s possible to pass parameters to the underlying GET request in a follow_redirect! by adding an additional arguments to the method.

def create
# do stuff
follow_redirect!(params: { user: params[:user_id] })
end

Action View

Add allocations to template rendering instrumentation

Aaron Patterson is on an ever-long performance optimization quest and his latest addition is allocations. Rails 6 will report on allocations made in views, which will allow developers be aware of how much time is spent in allocating and garbage collecting objects in the process’ memory.

  Rendered posts/_form.html.erb (Duration: 7.1ms | Allocations: 6004)
Rendered posts/new.html.erb within layouts/application (Duration: 8.3ms | Allocations: 6654)
Completed 200 OK in 858ms (Views: 848.4ms | ActiveRecord: 0.4ms | Allocations: 1539564)

Active Job

Added enqueue_retry.active_job, retry_stopped.active_job, and discard.active_job instrumentation hooks

Rails has a very extensive instrumentation hooks built into Active Support and it spans across the entire framework.

Allow passing multiple exceptions to #retry_on and #discard_on

It’s now possible to retry on multiple exceptions

retry_on Errno::ECONNREFUSED, SocketError, Timeout::Error, attempts: 5

Active Model

Allows configurable attribute name for #has_secure_password

This still defaults to an attribute named 'password', causing no breaking change. There is a new method #authenticate_XXX where XXX is the configured attribute name, making the existing #authenticate now an alias for this when the attribute is the default 'password'.

class User < ActiveRecord::Base
has_secure_password :recovery_password, validations: false
end
user = User.new()
user.recovery_password = "42password"
user.recovery_password_digest # => "$2a$04$iOfhwahFymCs5weB3BNH/uX..."
user.authenticate_recovery_password('42password') # => user

Active Storage

Uploaded files assigned to a record are persisted to storage when the record is saved instead of immediately

In rails 5.2 files were persisted immediately when assigned

@user.avatar = params[:avatar]

Use the ImageProcessing gem for Active Storage variants, and deprecate the MiniMagick backend

ImageProcessing support some better macros such as :resize_to_fit, :resize_to_fill and also has built in libvips which is in an alternative to ImageMagick.

Rails.application.config.active_storage.variant_processor = :vips

Action Cable

Merge action-cable-testing into Rails

This is a pretty cool addition, it lets us test action cable interactions more easily.

Taken from action-cable-testing gem on Github

The ActionCable javascript package has been converted from CoffeeScript to ES2015, and we now publish the source code in the npm distribution

I personally prefer ES2015 javascript to Coffeescript so I think it’s great.

Action Mailer

Add MailDeliveryJob for delivering both regular and parameterized mail, deprecate using DeliveryJob and Parameterized::DeliveryJob

DeliveryJob and Parameterized::DeliveryJob are deprecated in favor of MailDeliveryJob it is used for sending emails outside of the request-response cycle.

Action Support

Adds parallel testing to Rails

Parallel testing was a little bit hard up until Rails 6 especially in CI systems when you needed isolation between processes and interference with the database. I’ve written some weird database.yml s that rely on an environment variable that creates multiple databases in each of the CI build. Starting Rails 6 that would no longer be necessary as it is possible to just specify in Minitest

class ActiveSupport::TestCase
parallelize(workers: 2, with: :processes) # or :threads
end

Add support for tracing constant autoloads

Tracing constant autoloads is pretty easy now if you’re having trouble with autoloading constants on file changes.

if Rails.env.development?
ActiveSupport::Dependencies.logger = Rails.logger
ActiveSupport::Dependencies.verbose = true
end

Add cpu_time, idle_time, and allocations to ActiveSupport::Notifications::Event

ActiveSupport::Notifications.subscribe('wait') do |event|
@event = event
end

ActiveSupport::Notifications.instrument('wait') do
sleep 1
end

p @event.allocations # => 7
p @event.cpu_time # => 0.256
p @event.idle_time # => 1003.2399

Zeitwerk

Zeitwerk is a new code loader for Ruby. It is efficient, thread-safe, and matches Ruby semantics for constants.

General

Rails 6 requires Ruby 2.5.0 or newer

In order to upgrade to Rails 6 we must upgrade to Ruby 2.5+, quite obvious.

Ruby Inside

Ruby articles and posts

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch

Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore

Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store