Skip to content

Commit

Permalink
Raise a descriptive error when a store column is misconfigured
Browse files Browse the repository at this point in the history
If a developer has neglected to use a structured column type (hstore
or json) or to declare a serializer with `ActiveRecord.store`:

```ruby
  class User < ActiveRecord::Base
    store_accessor :settings, :notifications
  end
```

then a `ConfigurationError` will now be raised with a descriptive
error message when the accessor is read or written:

```ruby
  puts user.notifications
  # ActiveRecord::ConfigurationError: the column 'settings' has not
  # been configured as a store.  Please make sure the column is
  # declared serializable via 'ActiveRecord.store' or, if your
  # database supports it, use a structured column type like hstore or
  # json.
```

Previously, in this situation, a `NoMethodError` was raised when the
accessor was read or written:

```ruby
  puts user.notifications
  # NoMethodError: undefined method `accessor' for an instance of ActiveRecord::Type::Text
```

Raising a descriptive exception should help developers understand more
quickly what's wrong and how to fix it.

Closes rails#51699
  • Loading branch information
flavorjones committed May 23, 2024
1 parent 43e4916 commit 2bf7e25
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 1 deletion.
16 changes: 16 additions & 0 deletions activerecord/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
* Improve `ActiveRecord::Store` to raise a descriptive exception if the column is not either
structured (e.g., PostgreSQL +hstore+/+json+, or MySQL +json+) or declared serializable via
`ActiveRecord.store`.

Previously, a `NoMethodError` would be raised when the accessor was read or written:

NoMethodError: undefined method `accessor' for an instance of ActiveRecord::Type::Text

Now, a descriptive `ConfigurationError` is raised:

ActiveRecord::ConfigurationError: the column 'metadata' has not been configured as a store.
Please make sure the column is declared serializable via 'ActiveRecord.store' or, if your
database supports it, use a structured column type like hstore or json.

*Mike Dalessio*

* Fix inference of association model on nested models with the same demodularized name.

E.g. with the following setup:
Expand Down
6 changes: 5 additions & 1 deletion activerecord/lib/active_record/store.rb
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,11 @@ def write_store_attribute(store_attribute, key, value) # :doc:
end

def store_accessor_for(store_attribute)
type_for_attribute(store_attribute).accessor
type_for_attribute(store_attribute).tap do |type|
unless type.respond_to?(:accessor)
raise ConfigurationError, "the column '#{store_attribute}' has not been configured as a store. Please make sure the column is declared serializable via 'ActiveRecord.store' or, if your database supports it, use a structured column type like hstore or json."
end
end.accessor
end

class HashAccessor # :nodoc:
Expand Down
14 changes: 14 additions & 0 deletions activerecord/test/cases/store_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -359,4 +359,18 @@ def test_convert_store_attributes_from_Hash_to_HashWithIndifferentAccess_saving_
test "prefix/suffix do not affect stored attributes" do
assert_equal [:secret_question, :two_factor_auth, :login_retry], Admin::User.stored_attributes[:configs]
end

test "store_accessor raises an exception if the column is not either serializable or a structured type" do
user = Class.new(Admin::User) do
store_accessor :name, :color
end.new

assert_raises ActiveRecord::ConfigurationError do
user.color
end

assert_raises ActiveRecord::ConfigurationError do
user.color = "blue"
end
end
end

0 comments on commit 2bf7e25

Please sign in to comment.