-
Notifications
You must be signed in to change notification settings - Fork 21.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
undefined method `accessor' for #<ActiveModel::Type::Value:0x0000563c30ebdd50> #51699
Comments
Now that you know how to reproduce, you can use git bisect to find which change makes the exception to happen. Can you try that? |
@joesiewert, I've drafted the script to replicate the behavior. Rails version: Even with Rails 6.0.0, this is breaking. I believe there's a valid reason: in the migration, we haven't included the creation of a Adding the following line to the migration script should resolve the issue. t.json :metadata I was looking at hashicorp/vault-rails#138 and haven't found any migration with adding the column # frozen_string_literal: true
require "bundler/inline"
gemfile(true) do
source "https://rubygems.org"
gem "rails", "=6.0.0"
# If you want to test against edge Rails replace the previous line with this:
# gem "rails", github: "rails/rails", branch: "main"
gem "sqlite3", "~> 1.4"
end
require "active_record"
require "minitest/autorun"
require "logger"
# This connection will do for database-independent bug reports.
ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
ActiveRecord::Base.logger = Logger.new(STDOUT)
ActiveRecord::Schema.define do
create_table :posts do |t|
t.string :title
t.text :content
t.timestamps
end
end
class Post < ActiveRecord::Base
store_accessor :metadata, [:likes_count, :comments_count, :tags]
end
class BugTest < Minitest::Test
def test_store_accessors
post = Post.new(title: "Example Post", content: "This is an example post")
post.likes_count = 10
post.comments_count = 5
post.tags = ["ruby", "rails", "example"]
post.save
post = Post.last
assert_equal 10, post.likes_count
assert_equal 5, post.comments_count
assert_equal %w[ruby rails example], post.tags
end
end Output: E
Error:
BugTest#test_store_accessors:
NoMethodError: undefined method `accessor' for #<ActiveModel::Type::Value:0x000000011dd9e4a0>
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/activerecord-6.0.0/lib/active_record/store.rb:217:in `store_accessor_for'
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/activerecord-6.0.0/lib/active_record/store.rb:212:in `write_store_attribute'
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/activerecord-6.0.0/lib/active_record/store.rb:136:in `block (3 levels) in store_accessor'
51699.rb:38:in `test_store_accessors'
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/minitest-5.22.3/lib/minitest/test.rb:95:in `block (3 levels) in run'
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/minitest-5.22.3/lib/minitest/test.rb:192:in `capture_exceptions'
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/minitest-5.22.3/lib/minitest/test.rb:90:in `block (2 levels) in run'
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/minitest-5.22.3/lib/minitest.rb:324:in `time_it'
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/minitest-5.22.3/lib/minitest/test.rb:89:in `block in run'
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/minitest-5.22.3/lib/minitest.rb:423:in `on_signal'
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/minitest-5.22.3/lib/minitest/test.rb:240:in `with_info_handler'
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/minitest-5.22.3/lib/minitest/test.rb:88:in `run'
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/minitest-5.22.3/lib/minitest.rb:1138:in `run_one_method'
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/minitest-5.22.3/lib/minitest.rb:389:in `run_one_method'
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/minitest-5.22.3/lib/minitest.rb:376:in `block (2 levels) in run'
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/minitest-5.22.3/lib/minitest.rb:375:in `each'
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/minitest-5.22.3/lib/minitest.rb:375:in `block in run'
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/minitest-5.22.3/lib/minitest.rb:423:in `on_signal'
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/minitest-5.22.3/lib/minitest.rb:410:in `with_info_handler'
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/minitest-5.22.3/lib/minitest.rb:374:in `run'
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/minitest-5.22.3/lib/minitest.rb:206:in `block in __run'
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/minitest-5.22.3/lib/minitest.rb:206:in `map'
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/minitest-5.22.3/lib/minitest.rb:206:in `__run'
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/minitest-5.22.3/lib/minitest.rb:162:in `run'
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/minitest-5.22.3/lib/minitest.rb:86:in `block in autorun'
rails test 51699.rb:36 @rafaelfranca when we run this script with creating the column t.text :metadata # Running:
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/activemodel-6.0.0/lib/active_model/type/integer.rb:13: warning: Using the last argument as keyword parameters is deprecated; maybe ** should be added to the call
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/activemodel-6.0.0/lib/active_model/type/value.rb:8: warning: The called method `initialize' is defined here
E
Error:
BugTest#test_store_accessors:
NoMethodError: undefined method `accessor' for #<ActiveRecord::Type::Text:0x0000000134d43660>
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/activerecord-6.0.0/lib/active_record/store.rb:217:in `store_accessor_for'
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/activerecord-6.0.0/lib/active_record/store.rb:212:in `write_store_attribute'
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/activerecord-6.0.0/lib/active_record/store.rb:136:in `block (3 levels) in store_accessor'
51699.rb:39:in `test_store_accessors'
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/minitest-5.22.3/lib/minitest/test.rb:95:in `block (3 levels) in run'
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/minitest-5.22.3/lib/minitest/test.rb:192:in `capture_exceptions'
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/minitest-5.22.3/lib/minitest/test.rb:90:in `block (2 levels) in run'
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/minitest-5.22.3/lib/minitest.rb:324:in `time_it'
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/minitest-5.22.3/lib/minitest/test.rb:89:in `block in run'
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/minitest-5.22.3/lib/minitest.rb:423:in `on_signal'
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/minitest-5.22.3/lib/minitest/test.rb:240:in `with_info_handler'
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/minitest-5.22.3/lib/minitest/test.rb:88:in `run'
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/minitest-5.22.3/lib/minitest.rb:1138:in `run_one_method'
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/minitest-5.22.3/lib/minitest.rb:389:in `run_one_method'
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/minitest-5.22.3/lib/minitest.rb:376:in `block (2 levels) in run'
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/minitest-5.22.3/lib/minitest.rb:375:in `each'
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/minitest-5.22.3/lib/minitest.rb:375:in `block in run'
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/minitest-5.22.3/lib/minitest.rb:423:in `on_signal'
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/minitest-5.22.3/lib/minitest.rb:410:in `with_info_handler'
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/minitest-5.22.3/lib/minitest.rb:374:in `run'
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/minitest-5.22.3/lib/minitest.rb:206:in `block in __run'
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/minitest-5.22.3/lib/minitest.rb:206:in `map'
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/minitest-5.22.3/lib/minitest.rb:206:in `__run'
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/minitest-5.22.3/lib/minitest.rb:162:in `run'
/Users/manishsharma/.rvm/gems/ruby-2.7.8/gems/minitest-5.22.3/lib/minitest.rb:86:in `block in autorun' |
I think the issue here is that this code: store_accessor :metadata, [:likes_count, :comments_count, :tags] should be store :metadata, accessors: [:likes_count, :comments_count, :tags] I wonder if |
@flavorjones I don't think we should have any issues with the code regarding how we use it, as mentioned here: rails/activerecord/lib/active_record/store.rb Lines 40 to 72 in 343e781
I tried the code below as well, and we're encountering the same error. store :metadata, accessors: [:likes_count, :comments_count, :tags] Error:
BugTest#test_store_accessors:
NoMethodError: undefined method `accessor' for #<ActiveModel::Type::Value:0x000000011ad3c988> If we add the column metadata to the migration and we also need to add the ActiveRecord::Schema.define do
create_table :posts do |t|
t.string :title
t.text :content
t.text :metadata #Adding the column metadata solve the problem
t.timestamps
end
end store :metadata, accessors: [:likes_count, :comments_count, :tags], coder: JSON |
@maniSHarma7575 I'm not sure about that. Looking at the code, the original |
Yeah, @flavorjones you are correct. Here is the observered behaviour with Ruby: 1. Not creating the metadata column in migration and initializing store as following: store :metadata, accessors: [:likes_count, :comments_count, :tags] Output: Finished in 0.011299s, 88.5034 runs/s, 88.5034 assertions/s.
1) Failure:
BugTest#test_store_accessors [51699.rb:45]:
Expected: 10
Actual: nil
1 runs, 1 assertions, 1 failures, 0 errors, 0 skips 2. Creating metadata column in migration and initializing store as following: t.text :metadata store :metadata, accessors: [:likes_count, :comments_count, :tags] Output: Run options: --seed 8267
# Running:
D, [2024-05-06T09:35:58.280339 #2983] DEBUG -- : TRANSACTION (0.0ms) begin transaction
D, [2024-05-06T09:35:58.280448 #2983] DEBUG -- : Post Create (0.1ms) INSERT INTO "posts" ("title", "content", "metadata", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?) RETURNING "id" [["title", "Example Post"], ["content", "This is an example post"], ["metadata", "---\nlikes_count: 10\ncomments_count: 5\ntags:\n- ruby\n- rails\n- example\n"], ["created_at", "2024-05-06 04:05:58.279740"], ["updated_at", "2024-05-06 04:05:58.279740"]]
D, [2024-05-06T09:35:58.280578 #2983] DEBUG -- : TRANSACTION (0.0ms) commit transaction
D, [2024-05-06T09:35:58.284738 #2983] DEBUG -- : Post Load (0.0ms) SELECT "posts".* FROM "posts" ORDER BY "posts"."id" DESC LIMIT ? [["LIMIT", 1]]
.
Finished in 0.011449s, 87.3439 runs/s, 262.0316 assertions/s.
1 runs, 3 assertions, 0 failures, 0 errors, 0 skips 3. Not creating column and store initialization as follows: store_accessor :metadata, [:likes_count, :comments_count, :tags] Output: Run options: --seed 4507
# Running:
E
Finished in 0.004929s, 202.8809 runs/s, 0.0000 assertions/s.
1) Error:
BugTest#test_store_accessors:
NoMethodError: undefined method `accessor' for an instance of ActiveModel::Type::Value
rails/activerecord/lib/active_record/store.rb:220:in `store_accessor_for'
rails/activerecord/lib/active_record/store.rb:215:in `write_store_attribute'
rails/activerecord/lib/active_record/store.rb:139:in `block (3 levels) in store_accessor'
51699.rb:40:in `test_store_accessors'
1 runs, 0 assertions, 0 failures, 1 errors, 0 skips 4. Creating column and store initialization as follows: t.text :metadata store_accessor :metadata, [:likes_count, :comments_count, :tags] Output: Run options: --seed 31357
# Running:
E
Finished in 0.005465s, 182.9826 runs/s, 0.0000 assertions/s.
1) Error:
BugTest#test_store_accessors:
NoMethodError: undefined method `accessor' for an instance of ActiveRecord::Type::Text
rails/activerecord/lib/active_record/store.rb:220:in `store_accessor_for'
rails/activerecord/lib/active_record/store.rb:215:in `write_store_attribute'
rails/activerecord/lib/active_record/store.rb:139:in `block (3 levels) in store_accessor'
51699.rb:40:in `test_store_accessors'
1 runs, 0 assertions, 0 failures, 1 errors, 0 skips |
Thanks for the attention on this @maniSHarma7575 and @flavorjones , especially the distilled down reproduction script. My app configuration matches what you have in scenario 4, where the column is defined as |
@joesiewert OK, then you'll need to either
I'll try to whip up a PR to ensure that |
…a Store 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 by `store_accessor` with a descriptive error message: 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 ``` Raising an exception earlier, with a helpful message, should help developers understand more quickly what's wrong and how to fix it. Note that this change makes `store_accessor` call `type_for_attribute` which will potentially load the model's schema where it was not being loaded before. As a result, some small changes were needed to the test suite where the `json_data_type` table was not created early enough, and where an anonymous class needed to be bound to a real table. I don't think this should affect the majority of Store users. Closes rails#51699
…a Store 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 by `store_accessor` with a descriptive error message: 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 an exception earlier, with a helpful message, should help developers understand more quickly what's wrong and how to fix it. Note that this change makes `store_accessor` call `type_for_attribute` which will potentially load the model's schema where it was not being loaded before. As a result, some small changes were needed to the test suite where the `json_data_type` table was not created early enough, and where an anonymous class needed to be bound to a real table. I don't think this should affect the majority of Store users. Closes rails#51699
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 by `store_accessor` with a descriptive error message: ```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
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
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
I'm struggling to sort out an issue with
store_accessor
. Beginning in Rails 6.1, thestore_accessor_for
method now raisesNoMethodError
.I originally raised this over at hashicorp/vault-rails#138. While an update to that gem might be required, I think there was some change between Rails 6.0 and 6.1 that is causing this.
This issue also seems very similar to #43012.
Steps to reproduce
I have a branch up over at https://github.com/codeship/vault-rails/tree/rails-6.1 that reproduces the issue.
Expected behavior
In our currently working code on Rails 6.0.6.1
type_for_attribute(store_attribute).accessor
returnsActiveRecord::Store::IndifferentHashAccessor
and all is well.https://github.com/rails/rails/blob/v6.1.7.7/activerecord/lib/active_record/store.rb#L216-L218
Actual behavior
When trying to upgrade to Rails 6.1
type_for_attribute(store_attribute).accessor
instead raises:System configuration
Rails version: 6.1.7.7 (Observed the same issue on 7.0 and 7.1)
Ruby version: 2.7.8 (Observed the same issue using 3.3.0)
The text was updated successfully, but these errors were encountered: