trailblazer / reform

Form objects decoupled from models.
https://trailblazer.to/2.1/docs/reform.html
MIT License
2.49k stars 184 forks source link

Problem with delegation in forms in 2.6.1 / disposable 0.6.0 #534

Closed samstickland closed 2 years ago

samstickland commented 2 years ago

Complete Description of Issue

I have this in a contract:

money_property :fixed_charge, currency: ->(form) { form.default_currency }

...

private

delegate :assignment, to: :model
delegate :default_currency, to: :assignment, allow_nil: true

It works fine with Reform 2.6.0, but with 2.6.1 I get the following error:

  1) timesheets submission as a contractor submit a timesheet block with a note
     Failure/Error: delegate :assignment, to: :model

     ArgumentError:
       wrong number of arguments (given 2, expected 1)
     # /Users/samuelstickland/.rubies/ruby-3.0.2/lib/ruby/3.0.0/forwardable.rb:133:in `instance_delegate'
     # ./app/concepts/assignments/contract/rate.rb:56:in `<class:Rate>'
     # ./app/concepts/assignments/contract/rate.rb:2:in `<module:Contract>'
     # ./app/concepts/assignments/contract/rate.rb:1:in `<main>'
     # ./app/concepts/assignments/op/add_rate.rb:7:in `<class:Present>'
     # ./app/concepts/assignments/op/add_rate.rb:3:in `<class:AddRate>'
     # ./app/concepts/assignments/op/add_rate.rb:2:in `<module:Op>'
     # ./app/concepts/assignments/op/add_rate.rb:1:in `<main>'

Line 56 is the delegation line, line 2 is the class definition, which is weird.

If I remove the delegation and do this instead then it works:

def assignment
  model.assignment
end

def default_currency
  assignment&.default_currency
end

However, those methods can no longer be private, which suggests to me that execution scope has changed?

money_property is defined like this - not pasting the whole thing here - but you can see how the proc passed to currency is called.

  module Contract
    module Money
      extend ActiveSupport::Concern

      module ClassMethods
        def money_property(name, currency: nil, **options)
          ...
            define_method :"coerce_#{name}" do |value|
              currency_val = currency.respond_to?(:call) ? currency.call(self) : currency

                ...
            end
        end
      end
    end
  end

Has the self that is passed to call changed?

Steps to reproduce

Expected behavior

Should function as on 2.6.0

Actual behavior

Getting wrong number of arguments (given 2, expected 1) on use of delegate

System configuration

Reform version: 2.6.1 Ruby version: 3.0.2

Full Backtrace of Exception (if any)

     # /Users/samuelstickland/.rubies/ruby-3.0.2/lib/ruby/3.0.0/forwardable.rb:133:in `instance_delegate'
     # ./app/concepts/assignments/contract/rate.rb:56:in `<class:Rate>'
     # ./app/concepts/assignments/contract/rate.rb:2:in `<module:Contract>'
     # ./app/concepts/assignments/contract/rate.rb:1:in `<main>'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/bootsnap-1.9.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `require'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/bootsnap-1.9.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `block in require_with_bootsnap_lfi'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/bootsnap-1.9.1/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/bootsnap-1.9.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require_with_bootsnap_lfi'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/bootsnap-1.9.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:31:in `require'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/zeitwerk-2.5.1/lib/zeitwerk/kernel.rb:27:in `require'
     # ./app/concepts/assignments/op/add_rate.rb:7:in `<class:Present>'
     # ./app/concepts/assignments/op/add_rate.rb:3:in `<class:AddRate>'
     # ./app/concepts/assignments/op/add_rate.rb:2:in `<module:Op>'
     # ./app/concepts/assignments/op/add_rate.rb:1:in `<main>'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/bootsnap-1.9.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `require'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/bootsnap-1.9.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `block in require_with_bootsnap_lfi'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/bootsnap-1.9.1/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/bootsnap-1.9.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require_with_bootsnap_lfi'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/bootsnap-1.9.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:31:in `require'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/zeitwerk-2.5.1/lib/zeitwerk/kernel.rb:27:in `require'
     # ./spec/factories/rates.rb:41:in `block (3 levels) in <main>'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/factory_bot-6.2.0/lib/factory_bot/attribute_assigner.rb:50:in `instance_exec'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/factory_bot-6.2.0/lib/factory_bot/attribute_assigner.rb:50:in `build_class_instance'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/factory_bot-6.2.0/lib/factory_bot/attribute_assigner.rb:13:in `object'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/factory_bot-6.2.0/lib/factory_bot/evaluation.rb:13:in `object'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/factory_bot-6.2.0/lib/factory_bot/strategy/create.rb:9:in `result'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/factory_bot-6.2.0/lib/factory_bot/factory.rb:43:in `run'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/factory_bot-6.2.0/lib/factory_bot/factory_runner.rb:29:in `block in run'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/activesupport-6.1.4.1/lib/active_support/notifications.rb:205:in `instrument'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/factory_bot-6.2.0/lib/factory_bot/factory_runner.rb:28:in `run'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/factory_bot-6.2.0/lib/factory_bot/strategy_syntax_method_registrar.rb:28:in `block in define_singular_strategy_method'
     # ./spec/factories/assignments.rb:169:in `block (4 levels) in <main>'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/factory_bot-6.2.0/lib/factory_bot/callback.rb:13:in `instance_exec'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/factory_bot-6.2.0/lib/factory_bot/callback.rb:13:in `run'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/factory_bot-6.2.0/lib/factory_bot/callbacks_observer.rb:11:in `block in update'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/factory_bot-6.2.0/lib/factory_bot/callbacks_observer.rb:10:in `each'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/factory_bot-6.2.0/lib/factory_bot/callbacks_observer.rb:10:in `update'
     # /Users/samuelstickland/.rubies/ruby-3.0.2/lib/ruby/3.0.0/observer.rb:222:in `block in notify_observers'
     # /Users/samuelstickland/.rubies/ruby-3.0.2/lib/ruby/3.0.0/observer.rb:221:in `each'
     # /Users/samuelstickland/.rubies/ruby-3.0.2/lib/ruby/3.0.0/observer.rb:221:in `notify_observers'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/factory_bot-6.2.0/lib/factory_bot/evaluation.rb:24:in `notify'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/factory_bot-6.2.0/lib/factory_bot/strategy/create.rb:13:in `block in result'
     # <internal:kernel>:90:in `tap'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/factory_bot-6.2.0/lib/factory_bot/strategy/create.rb:9:in `result'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/factory_bot-6.2.0/lib/factory_bot/factory.rb:43:in `run'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/factory_bot-6.2.0/lib/factory_bot/factory_runner.rb:29:in `block in run'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/activesupport-6.1.4.1/lib/active_support/notifications.rb:205:in `instrument'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/factory_bot-6.2.0/lib/factory_bot/factory_runner.rb:28:in `run'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/factory_bot-6.2.0/lib/factory_bot/strategy_syntax_method_registrar.rb:28:in `block in define_singular_strategy_method'
     # ./spec/concepts/timesheets/submissions/features/timesheets_spec.rb:20:in `block (3 levels) in <top (required)>'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/memoized_helpers.rb:317:in `block (2 levels) in let'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/memoized_helpers.rb:157:in `block (3 levels) in fetch_or_store'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/memoized_helpers.rb:157:in `fetch'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/memoized_helpers.rb:157:in `block (2 levels) in fetch_or_store'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-support-3.10.3/lib/rspec/support/reentrant_mutex.rb:23:in `synchronize'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/memoized_helpers.rb:156:in `block in fetch_or_store'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/memoized_helpers.rb:155:in `fetch'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/memoized_helpers.rb:155:in `fetch_or_store'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/memoized_helpers.rb:317:in `block in let'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/memoized_helpers.rb:376:in `block in let!'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/example.rb:455:in `instance_exec'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/example.rb:455:in `instance_exec'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/hooks.rb:365:in `run'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/hooks.rb:529:in `block in run_owned_hooks_for'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/hooks.rb:528:in `each'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/hooks.rb:528:in `run_owned_hooks_for'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/hooks.rb:615:in `block in run_example_hooks_for'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/hooks.rb:614:in `reverse_each'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/hooks.rb:614:in `run_example_hooks_for'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/hooks.rb:484:in `run'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/example.rb:502:in `run_before_example'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/example.rb:261:in `block in run'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/example.rb:508:in `block in with_around_and_singleton_context_hooks'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/example.rb:465:in `block in with_around_example_hooks'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/hooks.rb:486:in `block in run'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/hooks.rb:626:in `block in run_around_example_hooks_for'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/example.rb:350:in `call'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-rails-5.0.2/lib/rspec/rails/adapters.rb:75:in `block (2 levels) in <module:MinitestLifecycleAdapter>'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/example.rb:455:in `instance_exec'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/example.rb:455:in `instance_exec'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/hooks.rb:390:in `execute_with'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/hooks.rb:628:in `block (2 levels) in run_around_example_hooks_for'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/example.rb:350:in `call'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/hooks.rb:629:in `run_around_example_hooks_for'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/hooks.rb:486:in `run'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/example.rb:465:in `with_around_example_hooks'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/example.rb:508:in `with_around_and_singleton_context_hooks'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/example.rb:259:in `run'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/example_group.rb:644:in `block in run_examples'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/example_group.rb:640:in `map'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/example_group.rb:640:in `run_examples'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/example_group.rb:606:in `run'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/example_group.rb:607:in `block in run'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/example_group.rb:607:in `map'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/example_group.rb:607:in `run'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/runner.rb:121:in `block (3 levels) in run_specs'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/runner.rb:121:in `map'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/runner.rb:121:in `block (2 levels) in run_specs'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/configuration.rb:2067:in `with_suite_hooks'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/runner.rb:116:in `block in run_specs'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/reporter.rb:74:in `report'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/runner.rb:115:in `run_specs'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/runner.rb:89:in `run'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/runner.rb:71:in `run'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/lib/rspec/core/runner.rb:45:in `invoke'
     # /Users/samuelstickland/.gem/ruby/3.0.2/gems/rspec-core-3.10.1/exe/rspec:4:in `<top (required)>'
     # /Users/samuelstickland/.gem/ruby/3.0.2/bin/rspec:25:in `load'
     # /Users/samuelstickland/.gem/ruby/3.0.2/bin/rspec:25:in `<top (required)>'
     # /Users/samuelstickland/.rubies/ruby-3.0.2/lib/ruby/site_ruby/3.0.0/bundler/cli/exec.rb:58:in `load'
     # /Users/samuelstickland/.rubies/ruby-3.0.2/lib/ruby/site_ruby/3.0.0/bundler/cli/exec.rb:58:in `kernel_load'
     # /Users/samuelstickland/.rubies/ruby-3.0.2/lib/ruby/site_ruby/3.0.0/bundler/cli/exec.rb:23:in `run'
     # /Users/samuelstickland/.rubies/ruby-3.0.2/lib/ruby/site_ruby/3.0.0/bundler/cli.rb:478:in `exec'
     # /Users/samuelstickland/.rubies/ruby-3.0.2/lib/ruby/site_ruby/3.0.0/bundler/vendor/thor/lib/thor/command.rb:27:in `run'
     # /Users/samuelstickland/.rubies/ruby-3.0.2/lib/ruby/site_ruby/3.0.0/bundler/vendor/thor/lib/thor/invocation.rb:127:in `invoke_command'
     # /Users/samuelstickland/.rubies/ruby-3.0.2/lib/ruby/site_ruby/3.0.0/bundler/vendor/thor/lib/thor.rb:392:in `dispatch'
     # /Users/samuelstickland/.rubies/ruby-3.0.2/lib/ruby/site_ruby/3.0.0/bundler/cli.rb:31:in `dispatch'
     # /Users/samuelstickland/.rubies/ruby-3.0.2/lib/ruby/site_ruby/3.0.0/bundler/vendor/thor/lib/thor/base.rb:485:in `start'
     # /Users/samuelstickland/.rubies/ruby-3.0.2/lib/ruby/site_ruby/3.0.0/bundler/cli.rb:25:in `start'
     # /Users/samuelstickland/.rubies/ruby-3.0.2/lib/ruby/gems/3.0.0/gems/bundler-2.2.30/exe/bundle:49:in `block in <top (required)>'
     # /Users/samuelstickland/.rubies/ruby-3.0.2/lib/ruby/site_ruby/3.0.0/bundler/friendly_errors.rb:103:in `with_friendly_errors'
     # /Users/samuelstickland/.rubies/ruby-3.0.2/lib/ruby/gems/3.0.0/gems/bundler-2.2.30/exe/bundle:37:in `<top (required)>'
     # /Users/samuelstickland/.rubies/ruby-3.0.2/bin/bundle:23:in `load'
     # /Users/samuelstickland/.rubies/ruby-3.0.2/bin/bundle:23:in `<main>'
apotonick commented 2 years ago

By the sounds of it this is a Ruby 3.0 issue where keyword arguments are not marked as kwargs using ** somewhere here?

apotonick commented 2 years ago

Pretty sure it's this: https://github.com/apotonick/disposable/commit/aec0870bfe28f993da3129fa25a3b5d612e2e463 When calling property or super you have to ** the option part. We can think about reverting this for now.

yogeshjain999 commented 2 years ago

Hmm but it works when delegate call is removed ?

@samstickland Could you please confirm this by reverting changes from https://github.com/apotonick/disposable/commit/aec0870bfe28f993da3129fa25a3b5d612e2e463# ?

apotonick commented 2 years ago

I'm very sure @samstickland overwrites #property somewhere and doesn't call super with **... :grimacing:

samstickland commented 2 years ago

@apotonick Thanks for the reply, but it's not that.. This is only part of the module that calls property:

def money_property(name, currency: nil, **options)
  property(name, **options)
apotonick commented 2 years ago

Please upgrade to disposable-0.6.1, I reverted the kws.

samstickland commented 2 years ago

@apotonick Thanks for the change - unfortunately I still get the same issue on 0.6.1.

Shall I try and put together a demonstration project?

apotonick commented 2 years ago

@samstickland Oh, how sad! I thought it fixed it. You must be doing something "naughty" then somewhere since we did not get any complaints so far :crossed_fingers: - that example project would be great! Let me know if you need help.

pauljacksonrodgers commented 2 years ago

I'm seeing the exact same delegation issue in 2.6.1, though only with EAGER_LOAD=1; otherwise no issue.

Replacing delegate :method, to: :instance with instance_delegate method: :instance "fixes" the issue, but doesn't seem ideal.

ArgumentError: wrong number of arguments (given 2, expected 1)
app/forms/my_form.rb:4:in `<class:MyForm>'
app/forms/my_form.rb:1:in `<top (required)>'
.rvm/gems/ruby-2.7.2/gems/zeitwerk-2.5.1/lib/zeitwerk/kernel.rb:27:in `require'
.rvm/gems/ruby-2.7.2/gems/zeitwerk-2.5.1/lib/zeitwerk/kernel.rb:27:in `require'
.rvm/gems/ruby-2.7.2/gems/zeitwerk-2.5.1/lib/zeitwerk/loader/helpers.rb:95:in `const_get'
.rvm/gems/ruby-2.7.2/gems/zeitwerk-2.5.1/lib/zeitwerk/loader/helpers.rb:95:in `cget'
.rvm/gems/ruby-2.7.2/gems/zeitwerk-2.5.1/lib/zeitwerk/loader.rb:232:in `block (2 levels) in eager_load'
.rvm/gems/ruby-2.7.2/gems/zeitwerk-2.5.1/lib/zeitwerk/loader/helpers.rb:26:in `block in ls'
.rvm/gems/ruby-2.7.2/gems/zeitwerk-2.5.1/lib/zeitwerk/loader/helpers.rb:18:in `each_child'
.rvm/gems/ruby-2.7.2/gems/zeitwerk-2.5.1/lib/zeitwerk/loader/helpers.rb:18:in `ls'
.rvm/gems/ruby-2.7.2/gems/zeitwerk-2.5.1/lib/zeitwerk/loader.rb:227:in `block in eager_load'
apotonick commented 2 years ago

@pauljacksonrodgers Where do you add that line? Can I see the form class?

majksner commented 2 years ago

Experiencing the same problem, happy to provide more info if necessary.

apotonick commented 2 years ago

@majksner A mini Rails app provoking the error would be great, we tried and couldn't make this bug "work"! :bomb: :joy_cat:

majksner commented 2 years ago

@apotonick

Here you go:

  1. Clone repo https://github.com/majksner/reform-issue-534
  2. bundle
  3. bundle exec rails s
  4. go to http://127.0.0.1:3000/welcome

Code is a bit messy, but this was the quickest thing to do.

Let me know if you need anything else.

apotonick commented 2 years ago

Thanks for the repo, @majksner! I was able to make it work, but it's a weird error, I suspect ActiveSupport's delegate to be the problem source.

Here's how I fixed it.

  class Factory < Reform::Form

    model :project
    property :state

    extend Forwardable
    def_delegators :model, :name
apotonick commented 2 years ago

This also works: delegate :name => :model It seems to be a change in Forwardable? Where does this :to option come from in the first place?

majksner commented 2 years ago

That works as well. delegate method is defined in https://github.com/rails/rails/blob/v6.1.4/activesupport/lib/active_support/core_ext/module/delegation.rb

apotonick commented 2 years ago

So ActiveSupport::delegate is the problem :wink: No idea though why this arises with Reform 2.6.1?

majksner commented 2 years ago

delegate :name, to: :model works fine if I use Reform 2.6.0. I see in the Gemfile.lock that disposable dependency is updated to newer version.

apotonick commented 2 years ago

@majksner And that disposable update is the only change?

apotonick commented 2 years ago

I think the ActiveSupport::delegate method/module is included too early in 2.6.1 for whatever reasons, which makes you use the same-named Forwardabledelegation :bomb: I hate Ruby's include magic... I think I know where to "fix" that.

majksner commented 2 years ago

Here is the diff from my Gemfile.lock

Screenshot 2021-12-01 at 12 39 34 Screenshot 2021-12-01 at 12 40 31
apotonick commented 2 years ago

Thanks @majksner :green_heart: Here's the problem: https://github.com/apotonick/disposable/commit/979dc5f4950881c913263340a12628ec1ea52566#diff-cbfbccff8b533b3c195c7058cf7245b5559ecf5f0a16b4e7b83390a2ade42be6R1 The underlying Twin (which is the form) now uses Forwardable which overrides the same-named method haha. I hate Ruby.

apotonick commented 2 years ago

Whoops, that wasn't supposed to close this ticket. :laughing:

@majksner @samstickland Could you kindly test this? It fixes the example repo.

In your Gemfile, add

gem "disposable", github: "apotonick/disposable"

majksner commented 2 years ago

@apotonick It works!

apotonick commented 2 years ago
Pushing gem to https://rubygems.org...
Successfully registered gem: disposable (0.6.2)

On Wed, Dec 1, 2021 at 1:13 PM Nikola Majksner @.***> wrote:

@apotonick https://github.com/apotonick It works!

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/trailblazer/reform/issues/534#issuecomment-983582656, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAACRJQWQAEYG5WJDSSPBPDUOYGNHANCNFSM5IMELFCQ . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.

apotonick commented 2 years ago

I blogged about this https://dev.to/trailblazer/dont-mix-forwardable-and-activesupportdelegate-5hmm