A new version of Rails always brings new and exciting features. This writeup takes a look at some of the things Rails 7 has in store for us.
To find these examples, I dug through the Changelogs and selected some of the features that have me most excited so far, primarily based on how I currently use Rails.
I encourage you to do the same - you may find something awesome that impacts a feature you use regulary or provides functionality you've been lying awake at night fantasizing about.
For each feature, I have included the PR that introduced it and the GitHub user who submitted the PR.
Note that several of these features have followup PRs from people making essential contributions by updating documentation, adding changelog entries, tweaking implementations, etc. If you are one of those folks, please know that while you're not given explicit credit here, we are very grateful for all you do! 🙏
Railties
The main Branch
PR 40254 by @prateekkish
When generating a new Rails project or plugin without the --skip-git
flag, the default branch of the created repository will now be main
instead of master
. If you've got a different branch set in your git config's init.defaultBranch
, that default will be used instead.
Rails began initializing the Git repository in 5.1 via PR 27632 by @dixpac.
benchmark Anywhere
PR 40734 by @semaperepelitsa
This PR adds the ActiveSupport::Benchmarkable.benchmark
method to the Rails
namespace, which allows you to easily benchmark a block of code anywhere without having to declare a logger
or extend
/include
the ActiveSupport::Benchmarkable
module.
To use the new functionality, you'd do something like this:
Rails.benchmark('Print bar') do
# code to benchmark
100.times { puts 'bar' }
end
After your code executes, the message you provided and the time it took the code to execute in milliseconds will be passed along to the Rails logger, ie: Print bar (0.6ms)
. The benchmark
call will return the return value of the block, 100
in this case.
Support Stats For Stylesheets and ERB Views
PR 40597 by @joelhawksley
If you've run rails stats
, you know that it provides various statistics about your app's codebase. This new functionality adds Views
and Stylesheets
to the output, providing stats for files in app/views
and app/assets/stylesheets
.
Note that stylesheets need to have a .css
or .scss
extension, and view files need to have the .erb
extension in order to be processed.
ActionPack
Redirect Back or To
PR 40671 by @dhh
Adds redirect_back_or_to(fallback, **)
as a nice shorthand for redirect_back(fallback_location:, **)
.
This avoids having to specify the fallback_location
kwarg (keyword argument) to redirect_back
. redirect_back_or_to
will redirect the user back to whence they came if it can, and will redirect to the fallback location if it can't.
The old syntax still works and hasn't been explicitly deprecated, but now redirect_back
calls redirect_back_or_to
under the hood.
Unpermitted Parameter Context
PR 41809 by @bbuchalter
This PR provides controller and request context when the parameters object is initialized so that when unpermitted attributes are logged, the controller, action, request, and filtered parameters will be logged as well.
ActionView
Lazy Load Images
PR 38452 by @jonathanhefner
Currently, apps can take advantage of the HTML standard's lazy loading of images by manually specifying the loading
attribute as lazy
in calls to image_tag
. This new configuration allows you to set the default to "lazy"
app-wide, so that the attribute will only need to be specified for places you want an image to be eager loaded.
Tag Attributes From Hash
PR 40657 by @seanpdoyle
This cool addition provides a slick way to tranform a hash of attributes into attributes on an ERB tag.
For example:
<div <%= tag.attributes({ id: 'percent-loaded', role: 'progressbar', aria: { valuenow: '75' }}) %>>
Would render:
<div id="percent-loaded" role="progressbar" aria-valuenow="75">
Perhaps not the greatest example, but if the hash were generated programmatically and required logic, this could be pretty useful.
ActiveModel
Add Numericality In Range Validation
PR 41022 by @mpapis
When validating numericality
of a model attribute, this new syntax lets you specify a range for the numericality validator versus having to sandwich between the greater_than_or_equal_to
and less_than_or_equal_to
options.
Example usage:
validates :latitude, numericality: { in: -90..90 }
ActiveRecord
Invert a where Clause
PR 40249 by @kddeisz
This addition provides a handy way to get at the inverse of a where clause by via invert_where
.
For example:
good_students = Student.where(grade: 80..100)
# SELECT \"students\".* FROM \"students\" WHERE \"students\".\"grade\" BETWEEN 80 AND 100
bad_students = good_students.invert_where
# SELECT \"students\".* FROM \"students\" WHERE NOT (\"students\".\"grade\" BETWEEN 80 AND 100)
Exclude a Record From Results
PR 41439 by @GlenCrawford
Ever need a way to get all records matching some condition except a record you already have? excluding
may be your jam.
Instead of:
other_users = User.where(rating: 80..).where.not(id: primary_user)
You can:
other_users = User.where(rating: 80..).excluding(primary_user)
Build or Create Association on Has One Through
PR 40007 by @perezperret
Enables the build_association
and create_association
functionality for has_one through:
relations. Previously these were not available on through
associations.
For example, if you had:
class Dog
has_many :toys
has_one :toy_box
end
class Toy
belongs_to :dog
has_one :toy_box, through: :dog
end
class ToyBox
belongs_to :dog
end
You'll now be able to:
toy.build_toy_box
# <ToyBox:0x00007f572007e170 id: nil, dog_id: 3>
Or:
toy.create_toy_box
# <ToyBox:0x00005601f2ac09a0 id: 5, dog_id: 3>
Respect Column Type When Calculating Average
PR 40351 by @schmijos
In prior versions of Rails, calling ActiveRecord::Caculations#calculate
with :average
would result in a BigDecimal
, even if a column was of a Float
or Integer
type.
For example:
Coordinate.last.longitude.class
# Float
Coordinate.calculate(:average, :longitude).class
# BigDecimal
Coordinate.calculate(:average, :longitude)
# 0.13002356e3
With the new behavior, it honors the type of the database column:
Coordinate.calculate(:average, :longitude).class
# Float
Coordinate.calculate(:average, :longitude)
# 130.02356
One of the motivators for this change was that JSON conversions of BigDecimal
result in a string value, whereas Float
results in a numeric value.
JSON.parse({ avg_longitude: 130.02356.to_d }.to_json)
# { "avg_longitude" => "130.02356" }
JSON.parse({ avg_longitude: 130.02356 }.to_json)
# { "avg_longitude" => 130.02356 }
Automatically Encrypt/Decrypt a Model Attribute
PR 41659 by @jorgemanrubia
Finally, we get to encrypts
.
This is deserving of a post all its own. The TLDR; version is that this feature adds a mechanism to auto-encrypt/decrypt an ActiveRecord
attribute by declaring encrypts attr_name
in the model. When a record is written to the database, it will automatically be encrypted, and when it is loaded from the database, the attribute will automatically be decrypted.
encrypts
also provides a workflow for changing the encryption scheme being used, without needing to re-encrypt all previously encrypted records under the new scheme.
Data can be encrypted in a non-deterministic manner (encrypting the same text twice will result in different ciphertexts), or can be encrypted deterministically - which allows querying the encrypted attribute.
Other niceties are the capability to encrypt Action Text
and to filter encrypted attributes from the application log files.
It really does quite a lot and provides several ways to customize behavior, depending on your needs.
What Else?
I touched on the things I am most excited about so far, but there is other great work underway. ActionPack, ActionView, ActiveRecord, and ActiveSupport in particular, all have rapidly growing lists of changes.
Thanks again to all the contributors who are making this next release possible. It's shaping up nicely!
Top comments (1)
Thanks for the writeup! This was a great way to check in on whats coming up with Rails.