default_value_for icon indicating copy to clipboard operation
default_value_for copied to clipboard

Fails with wrong number of arguments when used inside a subclass in Ruby 2.6+

Open dmeranda opened this issue 5 years ago • 3 comments

If using default_value_for within a subclass of another model, then the class instance initialization will fail with: ArgumentError (wrong number of arguments (given 2, expected 0..1))

This is version 3.3.0 and using all combinations of Ruby 2.6.5 and 2.7, and with Rails 5.2 and 6.0.

For example consider the classes:

class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true
end

class Example < ApplicationRecord
  default_value_for :name, "Hello"
end

Then calling Example.new will abort with the error. If on the other hand that were to subclass directly from ActiveRecord::Base instead of ApplicationRecord then it works fine.

I think I've tracked it down to calling super() within the initialize method. If I replace the code in default_value_for.rb

  module InstanceMethods
    def initialize(attributes = nil, options = {})
      ...
      if self.class.respond_to? :protected_attributes
        super(attributes, options)

with

  module InstanceMethods
    def initialize(attributes = nil, options = {})
      ..
      if self.class.respond_to? :protected_attributes
        super(attributes.merge(options))   # <<<< CHANGE THIS LINE

then it seems to work fine. Though I am not comfortable that this is the correct change to make.

dmeranda avatar Mar 04 '20 00:03 dmeranda

Thanks for your contribution. I just recently started helping to maintain this gem. Is this still an issue? Note, we dropped support for rubies less than 3.0 in 4.0. Version 3.6.x supports rubies less than 3.0. Please open if there is still a related issue in master with ruby 3.0-3.3. Thanks!

jrafanie avatar Nov 11 '24 19:11 jrafanie

Thanks for merging this; we've been using my commit/patch for several years now without issue. I'm not sure if is still an issue, though I suspect this fix still works.

When jumping to Rails 7.2 the built-in ActiveRecord 'attribute' method can now do much of what this gem does; as you can finally set a default value for an attribute without also needing to provide the data type:

# Rails 7.2+
attribute :foo, default: 'bar'
attribute :serialnumber, default: -> { SecureRandom.uuid }

In Rails 7.1 or prior this was more difficult to use for this purpose because you had to provide the data type, rather than letting it detect it from the DB schema.

dmeranda avatar Nov 12 '24 09:11 dmeranda

Thanks, I didn't merge it yet. I'll try to better understand if we can add it.

Yes, the attribute api handles a lot of the basics of this gem. Where it's lacking is masking "changed?" and deriving defaults based on an instance of the object, namely, the block notation. I'll reopen this and see if I can figure out if the change is still needed. Thanks for the information.

jrafanie avatar Nov 12 '24 23:11 jrafanie