GithubHelp home page GithubHelp logo

Comments (6)

flavorjones avatar flavorjones commented on June 19, 2024 1

@maniSHarma7575 I'm not sure about that. Looking at the code, the original store call is needed to set up the serializer on an existing column, and I think this is the underlying issue. (I'm using Rails edge in my analysis.) Regardless I think store_accessor should detect when there's no serializer associated and raise an error.

from rails.

rafaelfranca avatar rafaelfranca commented on June 19, 2024

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?

from rails.

maniSHarma7575 avatar maniSHarma7575 commented on June 19, 2024

@joesiewert, I've drafted the script to replicate the behavior.

Rails version: 6.0.0
Ruby version: ruby 2.7.8p225 (2023-03-30 revision 1f4d455848) [arm64-darwin22]

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 metadata column.

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 features into the database.

# 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 metadata as an text instead of the json the script throws an error detailed below. Is this desired behaviour?

    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'

from rails.

flavorjones avatar flavorjones commented on June 19, 2024

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 store_accessor should raise an exception if it's not going to do what the user expects? I would need to dig deeper to understand ActiveRecord::Store before speculating more.

from rails.

maniSHarma7575 avatar maniSHarma7575 commented on June 19, 2024

ActiveRecord

@flavorjones I don't think we should have any issues with the code regarding how we use it, as mentioned here:

# class User < ActiveRecord::Base
# store :settings, accessors: [ :color, :homepage ], coder: JSON
# store :parent, accessors: [ :name ], coder: JSON, prefix: true
# store :spouse, accessors: [ :name ], coder: JSON, prefix: :partner
# store :settings, accessors: [ :two_factor_auth ], suffix: true
# store :settings, accessors: [ :login_retry ], suffix: :config
# end
#
# u = User.new(color: 'black', homepage: '37signals.com', parent_name: 'Mary', partner_name: 'Lily')
# u.color # Accessor stored attribute
# u.parent_name # Accessor stored attribute with prefix
# u.partner_name # Accessor stored attribute with custom prefix
# u.two_factor_auth_settings # Accessor stored attribute with suffix
# u.login_retry_config # Accessor stored attribute with custom suffix
# u.settings[:country] = 'Denmark' # Any attribute, even if not specified with an accessor
#
# # There is no difference between strings and symbols for accessing custom attributes
# u.settings[:country] # => 'Denmark'
# u.settings['country'] # => 'Denmark'
#
# # Dirty tracking
# u.color = 'green'
# u.color_changed? # => true
# u.color_was # => 'black'
# u.color_change # => ['black', 'green']
#
# # Add additional accessors to an existing store through store_accessor
# class SuperUser < User
# store_accessor :settings, :privileges, :servants
# store_accessor :parent, :birthday, prefix: true
# store_accessor :settings, :secret_question, suffix: :config
# end
#

store_accessor provides an functionality to Add additional accessors to an existing store (From Parent Class) through store_accessor.

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 coder: JSON, the problem is solved.

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

from rails.

maniSHarma7575 avatar maniSHarma7575 commented on June 19, 2024

Yeah, @flavorjones you are correct.

Here is the observered behaviour with

Ruby: ruby 3.3.0 (2023-12-25 revision 5124f9ac75) [arm64-darwin23]
Rails: Rails Edge


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

from rails.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.