I'm upgrading my project from Rails '6.0.4.8' to '6.1.6.1'. Doing so breaks a lot of my rspec tests (as I somewhat expected). But I can't seem to figure out why I have a number of the form:
Failure/Error:
expect(log.errors.full_messages).to(include('error message'))
expected ["attribute name ^error message"] to include "error message"
Obviously with slight variations based on the type of test, but I'm not about to post all 50 of them here. From my understanding the "^" is supposed to trim the string to only contain everything following (i.e., get rid of the attribute name and keep the error message. Has this been changed in a newer version? And at any rate, this is checking for inclusion, not an exact match, so it's strange that it's failing.
Here are the packages I updated:
-gem 'rails', '6.0.4.8'
+gem 'rails', '6.1.6.1'
-gem 'acts-as-taggable-on', '~> 6.0'
+gem 'acts-as-taggable-on', '~> 7.0'
- gem 'rspec-rails', '4.0.0.beta3'
+ gem 'rspec-rails', '4.1.2'
- actioncable (6.0.4.8)
- actionpack (= 6.0.4.8)
+ actioncable (6.1.6.1)
+ actionpack (= 6.1.6.1)
+ activesupport (= 6.1.6.1)
- actionmailbox (6.0.4.8)
- actionpack (= 6.0.4.8)
- activejob (= 6.0.4.8)
- activerecord (= 6.0.4.8)
- activestorage (= 6.0.4.8)
- activesupport (= 6.0.4.8)
+ actionmailbox (6.1.6.1)
+ actionpack (= 6.1.6.1)
+ activejob (= 6.1.6.1)
+ activerecord (= 6.1.6.1)
+ activestorage (= 6.1.6.1)
+ activesupport (= 6.1.6.1)
- actionmailer (6.0.4.8)
- actionpack (= 6.0.4.8)
- actionview (= 6.0.4.8)
- activejob (= 6.0.4.8)
+ actionmailer (6.1.6.1)
+ actionpack (= 6.1.6.1)
+ actionview (= 6.1.6.1)
+ activejob (= 6.1.6.1)
+ activesupport (= 6.1.6.1)
- actionpack (6.0.4.8)
- actionview (= 6.0.4.8)
- activesupport (= 6.0.4.8)
- rack (~> 2.0, >= 2.0.8)
+ actionpack (6.1.6.1)
+ actionview (= 6.1.6.1)
+ activesupport (= 6.1.6.1)
+ rack (~> 2.0, >= 2.0.9)
- actiontext (6.0.4.8)
- actionpack (= 6.0.4.8)
- activerecord (= 6.0.4.8)
- activestorage (= 6.0.4.8)
- activesupport (= 6.0.4.8)
+ actiontext (6.1.6.1)
+ actionpack (= 6.1.6.1)
+ activerecord (= 6.1.6.1)
+ activestorage (= 6.1.6.1)
+ activesupport (= 6.1.6.1)
- actionview (6.0.4.8)
- activesupport (= 6.0.4.8)
+ actionview (6.1.6.1)
+ activesupport (= 6.1.6.1)
- activejob (6.0.4.8)
- activesupport (= 6.0.4.8)
+ activejob (6.1.6.1)
+ activesupport (= 6.1.6.1)
- activemodel (6.0.4.8)
- activesupport (= 6.0.4.8)
- activerecord (6.0.4.8)
- activemodel (= 6.0.4.8)
- activesupport (= 6.0.4.8)
- activestorage (6.0.4.8)
- actionpack (= 6.0.4.8)
- activejob (= 6.0.4.8)
- activerecord (= 6.0.4.8)
- marcel (~> 1.0.0)
- activesupport (6.0.4.8)
+ activemodel (6.1.6.1)
+ activesupport (= 6.1.6.1)
+ activerecord (6.1.6.1)
+ activemodel (= 6.1.6.1)
+ activesupport (= 6.1.6.1)
+ activestorage (6.1.6.1)
+ actionpack (= 6.1.6.1)
+ activejob (= 6.1.6.1)
+ activerecord (= 6.1.6.1)
+ activesupport (= 6.1.6.1)
+ marcel (~> 1.0)
+ mini_mime (>= 1.1.0)
+ activesupport (6.1.6.1)
- i18n (>= 0.7, < 2)
- minitest (~> 5.1)
- tzinfo (~> 1.1)
- zeitwerk (~> 2.2, >= 2.2.2)
- acts-as-taggable-on (6.5.0)
- activerecord (>= 5.0, < 6.1)
+ i18n (>= 1.6, < 2)
+ minitest (>= 5.1)
+ tzinfo (~> 2.0)
+ zeitwerk (~> 2.3)
+ acts-as-taggable-on (7.0.0)
+ activerecord (>= 5.0, < 6.2)
- autoprefixer-rails (10.4.2.0)
+ autoprefixer-rails (10.4.7.0)
- bcrypt (3.1.17)
+ bcrypt (3.1.18)
- bootsnap (1.11.1)
+ bootsnap (1.13.0)
- capybara (3.36.0)
+ capybara (3.37.1)
- erubi (1.10.0)
- excon (0.92.3)
+ erubi (1.11.0)
+ excon (0.92.4)
- faker (2.20.0)
+ faker (2.22.0)
- faraday (1.10.0)
- faraday-em_http (~> 1.0)
- faraday-em_synchrony (~> 1.0)
- faraday-excon (~> 1.1)
- faraday-httpclient (~> 1.0)
- faraday-multipart (~> 1.0)
- faraday-net_http (~> 1.0)
- faraday-net_http_persistent (~> 1.0)
- faraday-patron (~> 1.0)
- faraday-rack (~> 1.0)
- faraday-retry (~> 1.0)
+ faraday (2.4.0)
+ faraday-net_http (~> 2.0)
- faraday-em_http (1.0.0)
- faraday-em_synchrony (1.0.0)
- faraday-excon (1.1.0)
- faraday-httpclient (1.0.1)
- faraday-multipart (1.0.3)
- multipart-post (>= 1.2, < 3)
- faraday-net_http (1.0.1)
- faraday-net_http_persistent (1.2.0)
- faraday-patron (1.0.0)
- faraday-rack (1.0.0)
- faraday-retry (1.0.3)
+ faraday-net_http (2.1.0)
+ faraday-retry (2.0.0)
+ faraday (~> 2.0)
- fog-google (1.18.0)
+ fog-google (1.19.0)
- gapic-common (0.8.0)
- faraday (~> 1.3)
+ gapic-common (0.11.1)
+ faraday (>= 1.9, < 3.a)
+ faraday-retry (>= 1.0, < 3.a)
- googleapis-common-protos (>= 1.3.11, < 2.a)
- googleapis-common-protos-types (>= 1.0.6, < 2.a)
- googleauth (>= 0.17.0, < 2.a)
+ googleapis-common-protos (>= 1.3.12, < 2.a)
+ googleapis-common-protos-types (>= 1.3.1, < 2.a)
+ googleauth (~> 1.0)
- globalize (6.1.0)
+ globalize (6.2.1)
- google-apis-compute_v1 (0.34.0)
- google-apis-core (>= 0.4, < 2.a)
- google-apis-core (0.4.2)
+ google-apis-compute_v1 (0.45.0)
+ google-apis-core (>= 0.7, < 2.a)
+ google-apis-core (0.7.0)
- google-apis-dns_v1 (0.19.0)
- google-apis-core (>= 0.4, < 2.a)
- google-apis-iamcredentials_v1 (0.10.0)
- google-apis-core (>= 0.4, < 2.a)
- google-apis-monitoring_v3 (0.24.0)
- google-apis-core (>= 0.4, < 2.a)
- google-apis-pubsub_v1 (0.17.0)
- google-apis-core (>= 0.4, < 2.a)
- google-apis-sqladmin_v1beta4 (0.27.0)
- google-apis-core (>= 0.4, < 2.a)
- google-apis-storage_v1 (0.13.0)
- google-apis-core (>= 0.4, < 2.a)
+ google-apis-dns_v1 (0.23.0)
+ google-apis-core (>= 0.7, < 2.a)
+ google-apis-iamcredentials_v1 (0.13.0)
+ google-apis-core (>= 0.7, < 2.a)
+ google-apis-monitoring_v3 (0.32.0)
+ google-apis-core (>= 0.7, < 2.a)
+ google-apis-pubsub_v1 (0.24.0)
+ google-apis-core (>= 0.7, < 2.a)
+ google-apis-sqladmin_v1beta4 (0.32.0)
+ google-apis-core (>= 0.7, < 2.a)
+ google-apis-storage_v1 (0.17.0)
+ google-apis-core (>= 0.7, < 2.a)
- google-cloud-error_reporting-v1beta1 (0.4.5)
- gapic-common (>= 0.7, < 2.a)
+ google-cloud-error_reporting-v1beta1 (0.5.0)
+ gapic-common (>= 0.10, < 2.a)
- google-cloud-functions (1.1.3)
+ google-cloud-functions (1.2.0)
- google-cloud-functions-v1 (0.6.0)
- gapic-common (>= 0.7, < 2.a)
+ google-cloud-functions-v1 (0.8.0)
+ gapic-common (>= 0.10, < 2.a)
- google-cloud-logging (2.2.2)
+ google-cloud-logging (2.3.1)
- google-cloud-logging-v2 (0.7.0)
- gapic-common (>= 0.7, < 2.a)
+ google-cloud-logging-v2 (0.8.1)
+ gapic-common (>= 0.10, < 2.a)
- google-cloud-storage (1.36.2)
+ google-cloud-storage (1.38.0)
- google-apis-storage_v1 (~> 0.1)
+ google-apis-storage_v1 (~> 0.17.0)
- google-cloud-trace (0.41.3)
+ google-cloud-trace (0.42.1)
- google-cloud-trace-v1 (0.3.5)
- gapic-common (>= 0.7, < 2.a)
+ google-cloud-trace-v1 (0.4.0)
+ gapic-common (>= 0.10, < 2.a)
- google-cloud-trace-v2 (0.3.5)
- gapic-common (>= 0.7, < 2.a)
+ google-cloud-trace-v2 (0.4.0)
+ gapic-common (>= 0.10, < 2.a)
- google-protobuf (3.20.1)
+ google-protobuf (3.21.4)
- googleapis-common-protos-types (1.3.1)
+ googleapis-common-protos-types (1.3.2)
- googleauth (1.1.3)
+ googleauth (1.2.0)
- grpc (1.45.0)
+ grpc (1.48.0)
- grpc-google-iam-v1 (1.1.0)
+ grpc-google-iam-v1 (1.1.1)
- http-cookie (1.0.4)
+ http-cookie (1.0.5)
- i18n (1.10.0)
+ i18n (1.12.0)
- jquery-rails (4.4.0)
+ jquery-rails (4.5.0)
- json (2.6.1)
- jwt (2.3.0)
+ json (2.6.2)
+ jwt (2.4.1)
- minitest (5.15.0)
+ minitest (5.16.2)
- momentjs-rails (2.29.1.1)
+ momentjs-rails (2.29.4.1)
- msgpack (1.5.1)
+ msgpack (1.5.4)
- multipart-post (2.1.1)
- mysql2 (0.5.3)
+ mysql2 (0.5.4)
- nokogiri (1.13.6)
+ nokogiri (1.13.8)
- oj (3.13.11)
+ oj (3.13.19)
- pdf-reader (2.9.2)
+ pdf-reader (2.10.0)
- phony (2.19.11)
+ phony (2.20.0)
- rack (2.2.3.1)
+ rack (2.2.4)
- rack-test (1.1.0)
- rack (>= 1.0, < 3)
- rails (6.0.4.8)
- actioncable (= 6.0.4.8)
- actionmailbox (= 6.0.4.8)
- actionmailer (= 6.0.4.8)
- actionpack (= 6.0.4.8)
- actiontext (= 6.0.4.8)
- actionview (= 6.0.4.8)
- activejob (= 6.0.4.8)
- activemodel (= 6.0.4.8)
- activerecord (= 6.0.4.8)
- activestorage (= 6.0.4.8)
- activesupport (= 6.0.4.8)
- bundler (>= 1.3.0)
- railties (= 6.0.4.8)
+ rack-test (2.0.2)
+ rack (>= 1.3)
+ rails (6.1.6.1)
+ actioncable (= 6.1.6.1)
+ actionmailbox (= 6.1.6.1)
+ actionmailer (= 6.1.6.1)
+ actionpack (= 6.1.6.1)
+ actiontext (= 6.1.6.1)
+ actionview (= 6.1.6.1)
+ activejob (= 6.1.6.1)
+ activemodel (= 6.1.6.1)
+ activerecord (= 6.1.6.1)
+ activestorage (= 6.1.6.1)
+ activesupport (= 6.1.6.1)
+ bundler (>= 1.15.0)
+ railties (= 6.1.6.1)
- rails-i18n (7.0.3)
+ rails-i18n (7.0.5)
- railties (6.0.4.8)
- actionpack (= 6.0.4.8)
- activesupport (= 6.0.4.8)
+ railties (6.1.6.1)
+ actionpack (= 6.1.6.1)
+ activesupport (= 6.1.6.1)
- rake (>= 0.8.7)
- thor (>= 0.20.3, < 2.0)
+ rake (>= 12.2)
+ thor (~> 1.0)
- regexp_parser (2.3.1)
- representable (3.1.1)
+ regexp_parser (2.5.0)
+ representable (3.2.0)
- rmagick (4.2.5)
+ rmagick (4.2.6)
- rspec-rails (4.0.0.beta3)
+ rspec-rails (4.1.2)
- rspec-core (~> 3.8)
- rspec-expectations (~> 3.8)
- rspec-mocks (~> 3.8)
- rspec-support (~> 3.8)
+ rspec-core (~> 3.10)
+ rspec-expectations (~> 3.10)
+ rspec-mocks (~> 3.10)
+ rspec-support (~> 3.10)
- rubocop (1.28.2)
+ rubocop (1.33.0)
+ json (~> 2.3)
- rexml
- rubocop-ast (>= 1.17.0, < 2.0)
+ rexml (>= 3.2.5, < 4.0)
+ rubocop-ast (>= 1.19.1, < 2.0)
- rubocop-ast (1.17.0)
+ rubocop-ast (1.19.1)
- rubocop-performance (1.13.3)
+ rubocop-performance (1.14.3)
- rubocop-rails (2.14.2)
+ rubocop-rails (2.15.2)
- rubocop-rspec (2.10.0)
- rubocop (~> 1.19)
+ rubocop-rspec (2.12.1)
+ rubocop (~> 1.31)
- sdoc (2.3.2)
+ sdoc (2.4.0)
- selenium-webdriver (4.1.0)
+ selenium-webdriver (4.3.0)
- rubyzip (>= 1.2.2)
- shopify_api (10.0.3)
+ rubyzip (>= 1.2.2, < 3.0)
+ websocket (~> 1.0)
+ shopify_api (11.0.1)
- signet (0.16.1)
+ signet (0.17.0)
- faraday (>= 0.17.5, < 3.0)
+ faraday (>= 0.17.5, < 3.a)
- sorbet-runtime (0.5.9959)
+ sorbet-runtime (0.5.10274)
- ssrf_filter (1.0.7)
+ ssrf_filter (1.0.8)
- thread_safe (0.3.6)
- tilt (2.0.10)
+ tilt (2.0.11)
- tzinfo (1.2.10)
- thread_safe (~> 0.1)
+ tzinfo (2.0.5)
+ concurrent-ruby (~> 1.0)
- unf_ext (0.0.8.1)
- unicode-display_width (2.1.0)
+ unf_ext (0.0.8.2)
+ unicode-display_width (2.2.0)
+ websocket (1.2.9)
- zeitwerk (2.5.4)
+ zeitwerk (2.6.0)
- acts-as-taggable-on (~> 6.0)
+ acts-as-taggable-on (~> 7.0)
- rails (= 6.0.4.8)
+ rails (= 6.1.6.1)
- rspec-rails (= 4.0.0.beta3)
+ rspec-rails (= 4.1.2)
Let me know if I'm missing any noob details.
Like this probably very important detail:
$ bundle exec ruby --version
ruby 2.7.5p203 (2021-11-24 revision f69aeb8314) [x86_64-linux-musl]
And this:
$ cat /etc/os-release
NAME="Alpine Linux"
ID=alpine
VERSION_ID=3.15.4
PRETTY_NAME="Alpine Linux v3.15"
HOME_URL="https://alpinelinux.org/"
BUG_REPORT_URL="https://bugs.alpinelinux.org/"
For good measure:
$ bundle exec rspec --version
RSpec 3.11
- rspec-core 3.11.0
- rspec-expectations 3.11.0
- rspec-mocks 3.11.1
- rspec-rails 4.1.2
- rspec-support 3.11.0
Now feel free to tear me to shreds ;-)
The behavior you observed that error messages starting with a ^
omit the attribute name when calling full_messages
has never been a default Ruby on Rails feature.
Instead, plugins like custom-err-msg
or gems based on that plugin were used to add this behavior to Rails. Other options were to override Rails methods to add this functionality. See this old question for more examples of how this was done in the past.
Since Ruby on Rails 6.1 most of those techniques do not work anymore because in Ruby on Rails 6.1 errors are not a simple hash of attribute keys and message strings anymore. This pull request introduced an ActiveModel::Error
model that encapsulates error messages with Rails 6.1.
The recommended way to achieve the behavior you are looking for is to take advantage of the localization framework and override the default error message format that Rails uses when full_messages
is called. This can be done on different levels, application wide, just for one model, or even only for one specific attribute.
For example when you want to omit the attribute name on only want to show the error message for a Post#title
error, then add the following to your config/locales.en.yml
:
# config/locales/en.yml
en:
activerecord:
errors:
models:
post:
attributes:
title:
format: "%{message}" # default is "#{attribute} #{message}"
I suggest having a look at this blog article that gives tons of examples how to customize error messages depending on your needs.