Skip to content
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

factory_girl_rails/factory_bot_rails RuntimeError: can't modify frozen Array #247

Closed
torntrousers opened this issue Oct 26, 2017 · 29 comments

Comments

@torntrousers
Copy link

torntrousers commented Oct 26, 2017

I've followed the instructions in the blog post about how to make the factory_girl_rails/factory_bot_rails rename and now tests fail with 'can't modify frozen Array', eg:

RuntimeError:
  can't modify frozen Array
# ./config/environment.rb:5:in `<top (required)>'
# ./spec/rails_helper.rb:2:in `<top (required)>'
# ./spec/models/user_state_machine_spec.rb:1:in `<top (required)>'

I'm totally new to rails and Ruby so likely a user error, but what? Any pointers on what I'm doing wrong?

Thanks!

@joshuaclayton
Copy link
Contributor

@torntrousers to confirm, pre-rename, you were not seeing this error, correct?

Out of curiosity, is it possible you could provide the git diff from your change? If you're on a Mac, you should be able to run git show HEAD | pbcopy and paste in here, or send to me directly, if you've commited the changes.

Another possible culprit: you had a file with the name factory_girl in it somewhere in your repo, and when you ran the recommend grep/sed commands, it updated require "my/factory_girl/file" to require "my/factory_bot/file" without you moving the file.

Without being able to see what changed, it's difficult to nail down what the issue is, but those are the two places I'd start.

@torntrousers
Copy link
Author

torntrousers commented Oct 26, 2017

Yes the tests work fine if I change it all back to factory-girl. Here is the git diff:

git status
On branch factory-bot-name-change
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

	modified:   Gemfile
	modified:   Gemfile.lock
	modified:   config/application.rb
	modified:   spec/rails_helper.rb

no changes added to commit (use "git add" and/or "git commit -a")

and

git diff Gemfile
diff --git a/Gemfile b/Gemfile
index c50e9769..b89987dd 100644
--- a/Gemfile
+++ b/Gemfile
@@ -61,7 +61,7 @@ group :test do
   gem "capybara"
   gem "capybara-webkit"
   gem "database_cleaner"
-  gem "factory_girl_rails"
+  gem "factory_bot_rails"
   gem "faker"
   gem "fakeredis", require: "fakeredis/rspec"
   gem "multi_xml"
~/Development/phone-platform> git diff Gemfile.lock
diff --git a/Gemfile.lock b/Gemfile.lock
Rename factory-girl-rails to factory-bot-rails
index 35e081bd..20520657 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -200,10 +200,10 @@ GEM
       activemodel
     erubis (2.7.0)
     execjs (2.7.0)
-    factory_girl (4.8.0)
+    factory_bot (4.8.2)
       activesupport (>= 3.0.0)
-    factory_girl_rails (4.8.0)
-      factory_girl (~> 4.8.0)
+    factory_bot_rails (4.8.2)
+      factory_bot (~> 4.8.2)
       railties (>= 3.0.0)
     faker (1.8.4)
       i18n (~> 0.5)
@@ -517,7 +517,7 @@ DEPENDENCIES
   dotenv-rails (~> 2.1.0)
   dynamic_form
   email_validator
-  factory_girl_rails
+  factory_bot_rails
   faker
   fakeredis
   flag_shih_tzu

config/application.rb
@@ -61,7 +61,7 @@ class Application < Rails::Application
     config.generators do |g|
        g.test_framework      :rspec, :fixture => true
 -      g.fixture_replacement :factory_girl, :dir => "spec/factories"
 +      g.fixture_replacement :factory_bot, :dir => "spec/factories"
        g.template_engine     :haml
      end

spec/rails_helper.rb
@@ -44,7 +44,7 @@ def mock_mydrive_api
   config.include ControllerHelpers, type: :controller
    config.include Rack::Test::Methods, type: :rack
 -  config.include FactoryGirl::Syntax::Methods
 +  config.include FactoryBot::Syntax::Methods
  
    config.include RSpec::Rails::RequestExampleGroup, capybara_feature: true, type: :feature

@joshuaclayton
Copy link
Contributor

@torntrousers ah, excellent; can you check to see what changed in config/application.rb? Since that showed up in the original backtrace, I wonder if it got changed unexpectedly.

@torntrousers
Copy link
Author

diff --git a/config/application.rb b/config/application.rb
index 4a37cabd..a40b74f6 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -61,7 +61,7 @@ module PhonePlatform

     config.generators do |g|
       g.test_framework      :rspec, :fixture => true
-      g.fixture_replacement :factory_girl, :dir => "spec/factories"
+      g.fixture_replacement :factory_bot, :dir => "spec/factories"
       g.template_engine     :haml
     end

@joshuaclayton
Copy link
Contributor

@torntrousers ah, apologies - I missed this when you posted the diff.

There's nothing that's immediately obvious to me as actively causing this. Can you provide what command (or commands, if you're able to reproduce in other ways) that trigger this exception? (e.g. were you running rake, rspec spec, bundle exec rake, rails generate model foo bar baz)

The fact it travels all the way back to the application, which runs Bundler.require(*Rails.groups), makes me wonder if it's something with spring, maybe, since that's very much in the application load order and is operating on an array that could consider itself modified (since the list of gems has technically changed). Could you run spring stop and try whatever command(s) again?

@torntrousers
Copy link
Author

torntrousers commented Oct 26, 2017

After doing bundle install to get the error i do "bin/rake parallel:spec".
I've tried spring stop but it says spring is not running. So I tried restarting the mac but after that it still gets lots of "can't modify frozen Array" error. Then switching from my git branch with just this change back to master and doing bundle install and "bin/rake parallel:spec" and the tests all work fine again.
(and thanks for your help with this!)

@torntrousers
Copy link
Author

Sorted!
The problem was that the grep command given in the blog post to Replace All Constant References didn't actually change all the instances of FactoryGirl in the code base. After we found that and did a global change with Atom it all works fine.
This is an example diff of one of the files missed by the grep that I had to manually change:

git diff spec/factories/activation_code.rb
diff --git a/spec/factories/activation_code.rb b/spec/factories/activation_code.rb
index 493f7942..8c727cb5 100644
--- a/spec/factories/activation_code.rb
+++ b/spec/factories/activation_code.rb
@@ -1,4 +1,4 @@
-FactoryGirl.define do
+FactoryBot.define do
   factory :activation_code do
     code { Faker::Lorem.characters(6) }
     code_valid { true }

Something like this grep looks like it fixes it:
grep -rl 'FactoryGirl' ./ | xargs sed -i '' 's/FactoryGirl/FactoryBot/g'

@joshuaclayton
Copy link
Contributor

@torntrousers ah, excellent! I hadn't thought to ask about if other constants existed; I'd actually just attempted to recreate by adding parallel_tests to a repo 😃 to see if that was involved.

I'm glad to hear it! We ended up updating the command suggested in the upgrade doc since some people won't have rakefiles that include it (so, we added the -s flag for silencing unmatched files instead of failing).

I'm glad to hear it worked out, and thanks for your patience while we debugged; without access to the codebase, these problems are always a bit trickier!

@JalisoCSP
Copy link

This same issue seems to have happened to us on the update from 4.10.0 to 4.11.0, although the releases show "No notable changes"

We literally changed the version number and bundled.

@joshuaclayton
Copy link
Contributor

@JalisoCSP did any other gems get bumped in the upgrade? Can you provide a backtrace, and perhaps the line(s) that seem to be causing the problem?

@JalisoCSP
Copy link

JalisoCSP commented Aug 28, 2018

@joshuaclayton - Fast response! There was a few, but we've since narrowed it down to this gem being bumped - eg; we took this upgrade out and everything was fine.

Failure/Error: require File.expand_path("../../config/environment", __FILE__)

FrozenError:
  can't modify frozen Array

# ./config/environment.rb:17:in `<top (required)>'
# ./spec/spec_helper.rb:14:in `<top (required)>'
# ./spec/<our_spec_file>_spec.rb:1:in `<top (required)>'

respectively:
-> Rails.application.initialize!
-> require File.expand_path("../../config/environment", __FILE__)
-> require 'spec_helper'

(Edit: tag)

@joshuaclayton
Copy link
Contributor

@JalisoCSP is there further backtrace you can provide? There's nothing obvious/unique here that would point to FB - or really anything else - directly, so it's hard to provide any suggestions right now.

@JalisoCSP
Copy link

JalisoCSP commented Aug 29, 2018

@joshuaclayton nothing too useful, I'm afraid.

Here it is, in case it helps:

An error occurred while loading .<spec_path>_spec.rb.
Failure/Error: require File.expand_path("../../config/environment", __FILE__)

FrozenError:
  can't modify frozen Array
# [gem path]/actionpack-5.2.1/lib/action_dispatch/middleware/stack.rb:76:in `insert'
# [gem path]/actionpack-5.2.1/lib/action_dispatch/middleware/stack.rb:76:in `insert'
# [gem path]/sentry-raven-2.7.4/lib/raven/integrations/rails.rb:10:in `block in <class:Rails>'
# [gem path]/railties-5.2.1/lib/rails/initializable.rb:32:in `instance_exec'
# [gem path]/railties-5.2.1/lib/rails/initializable.rb:32:in `run'
# [gem path]/railties-5.2.1/lib/rails/initializable.rb:61:in `block in run_initializers'
# [gem path]/railties-5.2.1/lib/rails/initializable.rb:60:in `run_initializers'
# [gem path]/railties-5.2.1/lib/rails/application.rb:361:in `initialize!'
# ./config/environment.rb:17:in `<top (required)>'
# [gem path]/activesupport-5.2.1/lib/active_support/dependencies.rb:287:in `require'
# [gem path]/activesupport-5.2.1/lib/active_support/dependencies.rb:287:in `block in require'
# [gem path]/activesupport-5.2.1/lib/active_support/dependencies.rb:253:in `load_dependency'
# [gem path]/activesupport-5.2.1/lib/active_support/dependencies.rb:287:in `require'
# ./spec/spec_helper.rb:14:in `<top (required)>'
# [gem path]/activesupport-5.2.1/lib/active_support/dependencies.rb:287:in `require'
# [gem path]/activesupport-5.2.1/lib/active_support/dependencies.rb:287:in `block in require'
# [gem path]/activesupport-5.2.1/lib/active_support/dependencies.rb:253:in `load_dependency'
# [gem path]/activesupport-5.2.1/lib/active_support/dependencies.rb:287:in `require'
# .<spec_path>_spec.rb:1:in `<top (required)>'
# [gem path]/zeus-0.15.14/lib/zeus/load_tracking.rb:82:in `load'
# [gem path]/zeus-0.15.14/lib/zeus/load_tracking.rb:82:in `load'
# [gem path]/zeus-0.15.14/lib/zeus/load_tracking.rb:74:in `load'
# [gem path]/activesupport-5.2.1/lib/active_support/dependencies.rb:281:in `block in load'
# [gem path]/activesupport-5.2.1/lib/active_support/dependencies.rb:253:in `load_dependency'
# [gem path]/activesupport-5.2.1/lib/active_support/dependencies.rb:281:in `load'

This is on Rails 5.2.1 and Ruby 2.5.1

(Edits: Bad copy and paste when removing long [gem path] 👍)

@KelseyDH
Copy link

KelseyDH commented Sep 5, 2018

Having the same problem after changing to FactoryBot from FactoryGirl and factory_girl_rails to factory_bot_rails

NOTE: if you get this test error, the very first test error will give you more details on what's breaking.

@kirylrb
Copy link

kirylrb commented Sep 12, 2018

In my case issue was caused by rails_admin recent upgrade:

RuntimeError:
  Required middlewares for RailsAdmin are not added
  To fix tihs, add

    config.middleware.use ActionDispatch::Flash

  to config/application.rb.

@Mohakjuneja
Copy link

@joshuaclayton nothing too useful, I'm afraid.

Here it is, in case it helps:

An error occurred while loading .<spec_path>_spec.rb.
Failure/Error: require File.expand_path("../../config/environment", __FILE__)

FrozenError:
  can't modify frozen Array
# [gem path]/actionpack-5.2.1/lib/action_dispatch/middleware/stack.rb:76:in `insert'
# [gem path]/actionpack-5.2.1/lib/action_dispatch/middleware/stack.rb:76:in `insert'
# [gem path]/sentry-raven-2.7.4/lib/raven/integrations/rails.rb:10:in `block in <class:Rails>'
# [gem path]/railties-5.2.1/lib/rails/initializable.rb:32:in `instance_exec'
# [gem path]/railties-5.2.1/lib/rails/initializable.rb:32:in `run'
# [gem path]/railties-5.2.1/lib/rails/initializable.rb:61:in `block in run_initializers'
# [gem path]/railties-5.2.1/lib/rails/initializable.rb:60:in `run_initializers'
# [gem path]/railties-5.2.1/lib/rails/application.rb:361:in `initialize!'
# ./config/environment.rb:17:in `<top (required)>'
# [gem path]/activesupport-5.2.1/lib/active_support/dependencies.rb:287:in `require'
# [gem path]/activesupport-5.2.1/lib/active_support/dependencies.rb:287:in `block in require'
# [gem path]/activesupport-5.2.1/lib/active_support/dependencies.rb:253:in `load_dependency'
# [gem path]/activesupport-5.2.1/lib/active_support/dependencies.rb:287:in `require'
# ./spec/spec_helper.rb:14:in `<top (required)>'
# [gem path]/activesupport-5.2.1/lib/active_support/dependencies.rb:287:in `require'
# [gem path]/activesupport-5.2.1/lib/active_support/dependencies.rb:287:in `block in require'
# [gem path]/activesupport-5.2.1/lib/active_support/dependencies.rb:253:in `load_dependency'
# [gem path]/activesupport-5.2.1/lib/active_support/dependencies.rb:287:in `require'
# .<spec_path>_spec.rb:1:in `<top (required)>'
# [gem path]/zeus-0.15.14/lib/zeus/load_tracking.rb:82:in `load'
# [gem path]/zeus-0.15.14/lib/zeus/load_tracking.rb:82:in `load'
# [gem path]/zeus-0.15.14/lib/zeus/load_tracking.rb:74:in `load'
# [gem path]/activesupport-5.2.1/lib/active_support/dependencies.rb:281:in `block in load'
# [gem path]/activesupport-5.2.1/lib/active_support/dependencies.rb:253:in `load_dependency'
# [gem path]/activesupport-5.2.1/lib/active_support/dependencies.rb:281:in `load'

This is on Rails 5.2.1 and Ruby 2.5.1

(Edits: Bad copy and paste when removing long [gem path] 👍)

How did you resolve this? I've been struggling with the same error

@JalisoCSP
Copy link

How did you resolve this? I've been struggling with the same error

We never did. We're still on 4.10.0

CC: @Mohakjuneja

@composerinteralia
Copy link
Collaborator

The stack trace given on rails/rails#33745 looks fairly similar to this, and it seems to have been related to a rails_admin initializer running after the build_middleware_stack initializer.

The build_middleware_stack initializer freezes the middleware array:

From the stack trace in this issue, it looks like when sentry-raven inserts its middleware it is happening after the middleware array has been frozen.

I don't see how factory_bot_rails could have much effect here, since we don't do anything with middleware at all, but we did just got a new issue about this: #303.

@lstone
Copy link

lstone commented Nov 6, 2018

This happened to me when I declared two factories w/ the same name.

@composerinteralia
Copy link
Collaborator

See #303 (comment) for more details

@nezirz
Copy link

nezirz commented Mar 13, 2019

I had the same problem when tried to upgrade fromrails 5.2.0 to 5.2.2.1using bundle update rails command, its also updated many other gems one of them was factory_bot from 4.10.0 to 5.0.2 so solution was to downgrade to 4.10.0 by specifying the version number for factory_bot to gem "factory_bot_rails", "~> 4.10.0"

@composerinteralia
Copy link
Collaborator

@nezirz there were some deprecations in factory_bot 4.11, so you will want to upgrade to that version and deal with the warnings before upgrading to factory_bot 5.0.

@AlessandroMinali
Copy link

Great tip @composerinteralia.

basically to solve this issue:

rubocop \
  --require rubocop-rspec \
  --only FactoryBot/AttributeDefinedStatically \
  --auto-correct

The errors with 5.0 occur because of the deprecation of static var in factories. Gl all.

@pavkosykh
Copy link

Great tip @composerinteralia.

basically to solve this issue:

rubocop \
  --require rubocop-rspec \
  --only FactoryBot/AttributeDefinedStatically \
  --auto-correct

The errors with 5.0 occur because of the deprecation of static var in factories. Gl all.

Thanks a lot, this helped to solve problem!

@schmijos
Copy link
Contributor

The update 5.0.1 → 5.0.2 makes this occur again?
image

@composerinteralia
Copy link
Collaborator

@schmijos there are no intentional breaking changes from factory_bot_rails 5.0.1 to 5.0.2. The FrozenError is not coming from factory_bot (see #303 for details). If you want to see the underlying factory_bot error try running just one of the failing specs at a time.

@deepak-sweeten
Copy link

I was getting the same error. I fixed by removing require 'rails_helper' from spec files. It was causing the issue for me. I am not sure but it seems somewhere it was trying to load these helpers multiple time and it was causing can't modify frozen Array.

@marcelobarreto
Copy link

marcelobarreto commented May 25, 2019

In my case, just changed my factory field from password 123456 to password { 123456 } solved.

@mike927
Copy link

mike927 commented Oct 2, 2019

gem install rubocop-rspec
and then
rubocop --require rubocop-rspec --only FactoryBot/AttributeDefinedStatically --auto-correct

worked for me

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests