heartcombo / simple_form

Forms made easy for Rails! It's tied to a simple DSL, with no opinion on markup.
http://blog.plataformatec.com.br/tag/simple_form
MIT License
8.21k stars 1.32k forks source link

SystemStack Error when using config.wrappers in initializer (Rails 6.1 / Ruby 3) #1724

Closed itsterry closed 3 years ago

itsterry commented 3 years ago

Environment

This is a project which works beautifully with Rails 6.0 / Ruby 2.7.2 - we're upgrading it but having two issue which I think may be related (could be wrong, of course!)

Current behavior

Here's the SystemStackError trace:

➜ fanco git:(ruby3) ✗ rails c /Users/terry/.rvm/gems/ruby-3.0.0/gems/simple_form-5.0.3/lib/simple_form/wrappers/builder.rb:51:inuse': stack level too deep (SystemStackError) from /Users/terry/sites/fanco/config/initializers/simple_form.rb:60:in block (2 levels) in <top (required)>' from /Users/terry/.rvm/gems/ruby-3.0.0/gems/simple_form-5.0.3/lib/simple_form.rb:241:inbuild' from /Users/terry/.rvm/gems/ruby-3.0.0/gems/simple_form-5.0.3/lib/simple_form.rb:231:in wrappers' from /Users/terry/sites/fanco/config/initializers/simple_form.rb:16:inblock in <top (required)>' from /Users/terry/.rvm/gems/ruby-3.0.0/gems/simple_form-5.0.3/lib/simple_form.rb:289:in setup' from /Users/terry/sites/fanco/config/initializers/simple_form.rb:10:in<top (required)>' from /Users/terry/.rvm/gems/ruby-3.0.0/gems/activesupport-6.1.0/lib/active_support/dependencies.rb:326:in load' from /Users/terry/.rvm/gems/ruby-3.0.0/gems/activesupport-6.1.0/lib/active_support/dependencies.rb:326:inblock in load' ... 42 levels... from /Users/terry/.rvm/gems/ruby-3.0.0/gems/railties-6.1.0/lib/rails/command.rb:50:in invoke' from /Users/terry/.rvm/gems/ruby-3.0.0/gems/railties-6.1.0/lib/rails/commands.rb:18:in<top (required)>' from bin/rails:4:in require' from bin/rails:4:in

'`

Here's config/initializers/simple_form.rb (with commented lines omitted)

SimpleForm.setup do |config|
  config.wrappers :default,
                  class: :input,
                  hint_class: :field_with_hint,
                  error_class: :field_with_errors,
                  valid_class: :field_without_errors do |b|

    b.use :html5
    b.use :placeholder
    b.optional :maxlength
    b.optional :minlength
    b.optional :pattern
    b.optional :min_max
    b.optional :readonly
    b.use :label_input
    b.use :hint,  wrap_with: { tag: :span, class: :hint }
    b.use :error, wrap_with: { tag: :span, class: :error }
  end

  config.default_wrapper = :default
  config.boolean_style = :nested
  config.button_class = 'btn'
  config.error_notification_tag = :div
  config.error_notification_class = 'error_notification'
  config.browser_validations = false
  config.boolean_label_class = 'checkbox'
end

Here's my Gemfile:

source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

gem 'acts_as_list'
gem 'acts-as-taggable-on', git: 'https://github.com/morsedigital/acts-as-taggable-on'
gem 'after_party'
gem 'ancestry'
gem 'aws-sdk-s3'
gem 'axlsx', git: 'https://github.com/randym/axlsx.git', ref: 'c8ac844'

gem 'better_errors'
gem "binding_of_caller"
gem "browser", ">=2.5.1"
gem 'bullet', group: :development
gem 'byebug', platforms: [:mri, :mingw, :x64_mingw], groups: [:development, :test]

gem 'capistrano'
gem 'capybara', '>= 2.15', groups: [:test]
gem 'caxlsx_rails'
gem 'codacy-coverage', require: false
gem 'coveralls', groups: [:test]

gem 'decent_exposure'
gem 'devise'
gem 'dotenv-rails', require: 'dotenv/rails-now'

gem 'elasticsearch-model'
gem 'elasticsearch-rails'

gem 'faker'
gem 'factory_bot_rails'
gem 'faraday_middleware-aws-sigv4'
gem 'friendly_id'

gem 'google_drive'
gem 'gretel'
gem 'guard-rspec', groups: [:test]
gem 'guard-rubocop', groups: [:test]

gem 'i18n-debug', groups: [:development, :test]
gem 'i18n-tasks', groups: [:development, :test]
gem "iconv"
gem 'image_processing', '~> 1.2'
gem 'instagram'

gem 'jbuilder', '~> 2.5'

gem 'kaminari'

gem 'listen', groups: [:development]
gem "letter_opener", :group => :development

gem 'mini_magick'
gem 'morse_active_record_helpers'
gem 'morse_spec_helpers', '>=4.0.0', groups: [:development]
gem 'mysql2'

gem 'newrelic_rpm'

gem 'overcommit', groups: [:development]
gem 'omniauth'
gem 'omniauth-facebook'
gem 'omniauth-instagram'
gem 'omniauth-google-oauth2', '~> 0.8.0'

gem 'percy-capybara', '~> 4.0.0'
gem 'pry-byebug'
gem 'puma', '~> 3.11'

gem 'rails', '>=6.1'
gem 'rails_real_favicon', groups: [:development]
gem 'ransack'
gem 'recaptcha', require: 'recaptcha/rails'
gem 'record_tag_helper'
gem 'rest-client'
gem 'rollbar'
gem "roo", "~> 2.8.0"
gem 'rspec-rails', groups: [:development, :test]
gem 'rubocop', groups: [:test]
gem 'ruby-graphviz'
gem 'rubyzip', '>= 1.2.1'

gem 'sass-rails', '~> 5.0'
gem 'searchkick'
gem 'serviceworker-rails'
gem 'shoulda-matchers', groups: [:test]
gem 'sidekiq'
gem 'simple_form' 
gem 'simplecov', groups: [:test]
gem 'spring', groups: [:test]
gem 'spring-commands-rspec', groups: [:test]

gem 'turbolinks', '~> 5'
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]

gem 'web-console', github: 'rails/web-console', groups: [:development]
gem 'webdrivers', '~>3.0'
gem 'webpacker'
gem 'webpush'
gem 'workflow-activerecord'

Expected behavior

For everything to work with the SimpleForm loveliness that we use in all our projects (including other Ruby 3.0.0 / Rails 6.1 ones)

I've tried digging into the SimpleForm code to see if I can figure out what's making it loop (I think it's a loop), but not getting anywhere fast. any pointers would be appreciated!

carlosantoniodasilva commented 3 years ago

Can you please try SimpleForm master branch? Other people have hit a different RuntimeError with Ruby 3: https://github.com/heartcombo/simple_form/issues/1720, that was just fixed on master. Please check the Changelog for more info, and let me know how that worked, thanks.

itsterry commented 3 years ago

Hi @carlosantoniodasilva - that was an incredibly quick response: thank you!

Just tried this on master branch. Same result, I'm afraid. SystemStackError with the config.wrappers block. Hangs without that block. Works without SimpleForm

I'm going to dig into the Rails.application.initialize! process (again!) to see if I can figure out where exactly it's hanging

I'm not sure if this provides any useful info, but the hang is one where the Rails process (pid) needs to be forcibly killed with a kill -9 <pid> rather than just a Ctrl-C

carlosantoniodasilva commented 3 years ago

Alright, thanks for giving it a try and reporting back. I'll try setting up a new app from scratch with Rails 6.1 and Ruby 3, and see if I can find anything as well.

carlosantoniodasilva commented 3 years ago

A new app just generated with those Ruby/Rails specifications and SimpleForm master doesn't hang:

% ruby -v
ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-darwin20]

% rails -v
Rails 6.1.1

% bundle info simple_form
  * simple_form (5.0.3 cbcfe2e)
    Summary: Forms made easy!
    Homepage: https://github.com/heartcombo/simple_form
    Path: ~/.gem/ruby/3.0.0/bundler/gems/simple_form-cbcfe2e972fc

I'll try bundling with your config.

FWIW a previous report of "hanging" with the install generator seemed to be caused by Spring: https://github.com/heartcombo/simple_form/issues/1711, I couldn't repro that either.

itsterry commented 3 years ago

I know: it's weird. We have other Ruby 3.0.0 / Rails 6.1 projects that work wonderfully with SimpleForm.

I'm going to keep digging into Rails.application.initialize!. If I don't find anything there, my next step is to take out all the other gems and see if that fixes it, which I think would indicate a conflict. Could be wrong, but it's a plan of action...

carlosantoniodasilva commented 3 years ago

Sounds good, thanks. I'm trying to bundle that Gemfile but it's taking a while "Resolving dependencies..." too.

Looking some more at the stacktrace, the first line:

lib/simple_form/wrappers/builder.rb:51 https://github.com/heartcombo/simple_form/blob/v5.0.3/lib/simple_form/wrappers/builder.rb#L51

I wonder if there's something with autoload going on there. Just for the sake of ruling it out, are you using classic or Zeitwerk with that app, and is it any different than the other apps you mentioned?

I might not be able to look into this further today but I can check again tomorrow or later this week.

itsterry commented 3 years ago

Looks like zeitwerk, I think. Gemfile.lock says 2.4.2

carlosantoniodasilva commented 3 years ago

Ok, but that might still be set to classic even though the gem is part of the bundle, can you check for Rails.configuration.autoloader please? Thanks.

I was unable to bundle, "Resolving dependencies" seemed to get stuck. (even though it seemed like it was progressing, it took minutes without completing, not sure what's up.)

itsterry commented 3 years ago

Confirming: Rails.configuration.autoloader returns :zeitwerk

I stripped out all the gems except SimpleForm and put them back in one by one. Looks like we have issues whenever any one of the following gem versions is present:

ancestry 3.2.1 faker 2.15.1 i18n-debug 1.2.0 ransack 2.4.1

Interestingly, if I leave out all of those gems AND include the config.wrappers block in the initializer, the SystemStackError disappears and the application runs

If include any one of those gems AND the config.wrappers block, I get the SystemStackError If include any one of those gems AND NOT the config.wrappers block, the application hangs If I include all of those gems AND NOT SimpleForm, the application runs

All of the above are true when running SimpleForm from master or from gem version 5.0.3

I'm not sure if these details are of any use, but I'm providing them in case it sparks an idea

I'm going to investigate how those gems load in to see if I can spot anything relevant / any similarities

carlosantoniodasilva commented 3 years ago

Thanks for confirming about the autoloader and sharing these details.

I tried bundling just with those gems and a couple others (rails, simple_form, sqlite3, puma, sass-rails), and my test generated app still worked.

Can you share the Gemfile & Gemfile.lock with the minimal subset of gems above that you were able to repro? And maybe you can try isolating that on a separate app with those gems, see if you can repro it there?

itsterry commented 3 years ago

Will do. I was actually thinking of rebuilding the whole project from a new rails app, copying in the files I have in batches, so this may be the start of that

I’ll report back

On Thu, 21 Jan 2021 at 23:44, Carlos Antonio da Silva < notifications@github.com> wrote:

Thanks for confirming about the autoloader and sharing these details.

I tried bundling just with those gems and a couple others (rails, simple_form, sqlite3, puma, sass-rails), and my test generated app still worked.

Can you share the Gemfile & Gemfile.lock with the minimal subset of gems above that you were able to repro? And maybe you can try isolating that on a separate app with those gems, see if you can repro it there?

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/heartcombo/simple_form/issues/1724#issuecomment-765012609, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAXUS3TZVJUWFZ7ZGG5JQTS3C36JANCNFSM4WLBTMQQ .

--


Terry Shuttleworth

itsterry@gmail.com

Mobile: +44 (0) 77 68 91 81 93 Google Chat: itsterry@gmail.com Skype: itsterry LinkedIn: linkedin.com/in/itsterry WhatsApp: Nope.

sergiopantoja commented 3 years ago

Just hit this while trying to deploy Ruby 3.0.0 with Rails 6.1.1 to production. Oddly enough, I don't hit the error locally or on staging. Will look into this as well and report back if I find anything.

Here are the gems I share with @itsterry in case it helps triage some gem incompatibility:

gem 'aws-sdk-s3'
gem 'bullet', group: :development
gem 'byebug', platforms: [:mri, :mingw, :x64_mingw], groups: [:development, :test]
gem 'capybara', '>= 2.15', groups: [:test]
gem 'decent_exposure'
gem 'devise'
gem 'dotenv-rails', require: 'dotenv/rails-now'
gem 'faker'
gem 'factory_bot_rails'
gem 'image_processing', '~> 1.2'
gem 'kaminari'
gem 'listen', groups: [:development]
gem "letter_opener", :group => :development
gem 'omniauth'
gem 'omniauth-google-oauth2', '~> 0.8.0'
gem 'puma', '~> 3.11'
gem 'rails', '>=6.1'
gem 'rest-client'
gem 'rspec-rails', groups: [:development, :test]
gem 'rubocop', groups: [:test]
gem 'rubyzip', '>= 1.2.1'
gem 'sass-rails', '~> 5.0'
gem 'shoulda-matchers', groups: [:test]
gem 'sidekiq'
gem 'simple_form'
gem 'simplecov', groups: [:test]
gem 'spring', groups: [:test]
gem 'spring-commands-rspec', groups: [:test]
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
gem 'web-console', github: 'rails/web-console', groups: [:development]
gem 'webpacker'
carlosantoniodasilva commented 3 years ago

@sergiopantoja thanks, interesting to know that it only happens in actual production env. (I'm assuming staging uses a different Rails env in this case? Are there any noticeable config differences between the two?)

I tried running in production as well here with your Gemfile and didn't hit anything. 🤔 There must be something with the app config / load that we're missing and may be causing this.

LeonardoComar commented 3 years ago

@carlosantoniodasilva Greetings, any news for a version with suport to Ruby 3.0.0?

carlosantoniodasilva commented 3 years ago

@LeonardoComar I have been holding off releasing master to see if this here was a bigger issue and/or if we could more consistently reproduce, but it doesn't seem to be the case, so I guess I can prepare a new release this week if I don't hear otherwise here in the next couple of days. Thanks!

khustochka commented 3 years ago

I also experience this error in dev and test environment (haven't tried production). Ruby 3.0.0 Rails 6.1.1

In my case it is definitely caused by the presence of ancestry gem.

Looks like no one mentioned this, but at least in my case the order of gems in Gemfile matters: if _simpleform is listed after ancestry, this error is reproduced. If it is listed before ancestry, everything works as expected.

carlosantoniodasilva commented 3 years ago

@khustochka thanks for letting us know, that is good info. Any chance you can provide a small gist/app that reproduces it? Or at least the Gemfile/Gemfile.lock. I'm still unable to repro with these settings:

% ruby -v
ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-darwin20]

% bundle info rails
  * rails (6.1.1)
    Summary: Full-stack web application framework.
    Homepage: https://rubyonrails.org
        ...

% bundle info simple_form
  * simple_form (5.0.3)
    Summary: Forms made easy!
    Homepage: https://github.com/heartcombo/simple_form
    ...

% bundle info ancestry
  * ancestry (3.2.1)
    Summary: Organize ActiveRecord model into a tree structure
    Homepage: https://github.com/stefankroes/ancestry
        ...

And my Gemfile lists ancestry and simple_form at the bottom in that order: (bundled from my local master branch)

gem 'ancestry'
gem 'simple_form', path: '../simple_form'

This is a new Rails app but it was created without some of the frameworks, maybe that matters too in order to repro.

Also, FWIW, it seems ancestry itself does not support Ruby 3 & Rails 6.1 yet: https://github.com/stefankroes/ancestry/pull/525

khustochka commented 3 years ago

Looks like it goes beyond just ancestry. The smallest Gemfile I was able to reproduce this on is as follows:

source 'https://rubygems.org'
ruby '3.0.0'

gem 'rails', '~> 6.1.1'
gem 'sqlite3', '~> 1.4'
gem "puma"
gem "listen"

gem "ancestry", "3.2.1"
gem "simple_form", "5.0.3"
gem "hashie", "4.1.0"
gem "pry-byebug", "3.9.0"

Here is a demo app. (I also disabled spring and bootsnap for cleaner experiment but they seem to not matter).

But:

  1. If I move simple_form above ancestry - error is not reproduced.
  2. If I exclude only ancestry or only hashie - error is not reproduced.
  3. If I exclude only pry-byebug - app hangs when loading.

So some absolutely confusing interaction between zeitgeist, bundler (?) and a random set of other gems?

carlosantoniodasilva commented 3 years ago

Okay, thanks for that @khustochka, I was able to repro here with this limited gems in that order... really confusing, I'll see what I can find.

carlosantoniodasilva commented 3 years ago

Some investigation progress here and a possible solution: The stack traces all seem to point to this builder line: https://github.com/heartcombo/simple_form/blob/cbcfe2e972fc25a53474d72b256a7f6c389de545/lib/simple_form/wrappers/builder.rb#L51, which I thought at first could be an autoload thing, but the problem actually seems to be on the options.except call, as odd as it sounds.

I am able to load the console (rails c), but simply typing Hash.new.method(:except) hangs there. Interestingly enough, calling the method works: Hash.new.except(:foo)

I know that Ruby 3 has added Hash#except, and Rails now adds it conditionally only if the method isn't already there, to account for that.

I went looking into the other gems and found out that Ancestry seems to be messing with the I18n.load_path early on when it's loading. I tried commenting that out and I was able to run the rails server. My gut feeling is that this might be loading I18n way too soon in the boot process, so I tried a few other things here to delay the loading, but didn't think the culprit would be here anyway.

So I looked at I18n and noticed it is adding a refinement to Hash, which includes the except method. I believe this is the problem: for some reason that is not interacting well with the new Hash#except method in Ruby 3 I think, and is causing what we're seeing here. I tried skipping that method definition if the method is already defined, like Rails also does, and it worked. I couldn't repro it with just I18n itself though.

I have a branch with that change to i18n here: https://github.com/ruby-i18n/i18n/tree/ca-except-ruby3, @khustochka would you (or anyone else here) be able to try that out in your app and let me know how it goes?

If that works I'll work to get that into i18n itself. Thanks!

kbrock commented 3 years ago

@CarlosAlbertoSantos ancestry master is working with rails 6.0 and 6.1 for ruby 3.0

since I need to release a major change for ancestry, it will take a little while to get the next version out. In the meantime, I hope master will work for you. Let me know if it gives you any troubles

khustochka commented 3 years ago

@carlosantoniodasilva Thank you! My app works correctly when using that ca-except-ruby3 branch of i18n.

carlosantoniodasilva commented 3 years ago

That's awesome @khustochka, thanks for testing and reporting back. I opened a PR from that branch https://github.com/ruby-i18n/i18n/pull/557 to get the fix into I18n.

I'll be releasing SF with Ruby 3 support at some point soon.

carlosantoniodasilva commented 3 years ago

I just released v5.1.0 which should work with Ruby 3 (aside from the issue above which is not SF specific).

I'm gonna close this one for now, feel free to subscribe to the I18n issue to hear about updates there. Thanks all.

carlosantoniodasilva commented 3 years ago

FYI: I18n v1.8.9 was just released with the change I proposed to fix the hanging issue with Ruby 3, please give it a shot and report back there if you run into any trouble.

itsterry commented 3 years ago

@carlosantoniodasilva Just reporting in that all looks good now. Many, many thanks for your help with this one: hugely appreciated!

carlosantoniodasilva commented 3 years ago

@itsterry awesome, I'm really glad to hear that it worked! Thanks for reporting back.