Closed ravishwetha closed 6 years ago
I can't reproduce this with your steps.
If you created an application in the same state, will it reproduce in your environment?
@ravishwetha I recently saw something similar in one of my repos. It was an API only repo (not sure if that matters or not).
I ended up having to add:
require "active_storage/engine"
to the config/application.rb
file.
I believe this is because I upgraded a repo that did not have active storage, so it was not being auto-required properly on startup.
@y-yagi Haven't tried this, I am not exactly sure what you mean by 'same state'. Do you mean a new application with the same Gemfile and a Model using the "has_many_attached :documents" to see it if it works?
@jacobsmith It is not API only, I tried require "active_storage/engine"
in the file but I get the same error: undefined method `has_one_attached' for Model
. Yes I just upgraded an app in the hope of using ActiveStorage (it was not beforehand).
Do you mean a new application with the same Gemfile and a Model using the "has_many_attached :documents" to see it if it works?
Yes. I tried to reproduce this, but this issue could not be reproduced. Can you please provide a sample application that reproduces the issue?
I'm having the same issue, but adding require "active_storage/engine"
has not helped. Will continue investigating.
Branch with the error is here: https://github.com/crowdAI/crowdai/commit/83e07ea3c04816718b5cafa961320a6b8428c6ed
Have found the trigger ... will report back soon.
@seanfcarroll I you don't need to mention gem 'activestorage'
in the gemfile. Could you try with removing that.
ah yes, I have found there is a conflict with some other metaprogramming code we are using
gem 'rails-gdpr-export'
I should have some time to properly analyse it tomorrow or Thursday. Will post back here.
On tenterhooks here! Have exactly the same error. Not using that particular gem but perhaps it's a dependency.
To follow your lead, I just created a new Rails app and a single model file with a has_one_attached
call in it; added the GDPR gem and it still worked, did not throw the undefined method error.
OK, I figured out what was causing the issue in my case. It was a flavour of circular dependency. Reproduce thusly:
# config/initializers/thing.rb
GLOBAL_THING = { thing: Thing::THING }.freeze
# app/models/thing.rb
class Thing < ActiveRecord::Base
THING = 'Thing'.freeze
has_one_attached :thingie
Removing the constant declaration from the initializer file and putting it into the relevant model fixed the problem.
Spent about half a day on this and in the end have decided to take another approach to solve my GDPR download requirements.
The GDPR export gem and ActiveStorage are somehow conflicting. The symptoms were that if a model was annotated by the GDPR gem, the has_one_attached method was not available to the model.
I couldn't see anything in the GDPR export gem that looks like it should conflict with core Rails, so I think there is still could be an undiagnosed bug in ActiveStorage.
CC @grischoun
@seanfcarroll
I tried has_one_attached
with GDPR export gem, but it seems work correctly.
https://github.com/y-yagi/reproduce_32933
Can you please provide a sample application that reproduces the issue?
I have made a sample application the reproduces the issue. It uses the clearance gem. https://github.com/lethan/clearance_active_storage
I was seeing this issue as well. By looking at the trace I found I was referencing the model with the has_one_attached
call in an initializer. When the constant autoloader kicked in and tried to load that class the ActiveStorage macros were not available causing the NoMethodError to bubble up. I was able to patch it in my case by removing the direct reference to the constant in my initializer. For some reason it looks like ActiveStorage is not fully set up when the initializers are run.
I'm not sure my issue is the exact issue happening here, but hopefully it will help in digging to the bottom of it.
@lethan Thanks for the sample application. I can reproduce.
@tpett
Thanks for the detailed explanation. You are right.
In Active Storage, define methods such as has_one_attached
when loading Active Record is executed.
https://github.com/rails/rails/blob/5dc72378b783e924c5bf079ca660388ec4ac9224/activestorage/lib/active_storage/engine.rb#L60..L66
If a model is a trigger for loading Active Record(e.g: by referring directly the model in initialize), model will be loaded before the above hook, resulting in raise ArgumentError
.
If possible, avoiding referencing model directly with the initializer is a temporary workaround.
There are two problem on loading Active Record models in initializers, one of them is that it will mess with the code reload, those models may not be able to be reloaded anymore.
Another one is that it will make active record load early, and that will not only causes problems like this one in this issue, but also other problems with many other gems and even with active record configurations.
That being said, the correct fix is to not load models in initializers. The application is not initialized yet, so there is no guarantee it will work.
Sometimes models have to be loaded in initializers, for instance when using the Apartment
gem with excluded models. Fortunately, there's a solution:
Given an Account
model, with has_one_attached :logo
, the workaround is:
Model:
- has_one_attached :logo
+ has_one :logo_attachment, -> { where(name: 'logo') }, class_name: "ActiveStorage::Attachment", as: :record, inverse_of: :record, dependent: false
+ has_one :logo_blob, through: :logo_attachment, class_name: "ActiveStorage::Blob", source: :blob
Controller:
# In create/update action, before calling @account.save/@account.update:
+ if account_params[:logo].present?
+ blob = ActiveStorage::Blob.build_after_upload(
+ io: account_params[:logo],
+ filename: account_params[:logo].original_filename,
+ content_type: account_params[:logo].content_type
+ )
+ @account.logo_blob = blob
+ end
Other methods:
- @account.logo.attached?
+ @account.logo_attachment.present?
- rails_blob_path(@account.logo)
+ rails_blob_path(@account.logo_blob)
- @account.logo.variant(...)
+ @account.logo_blob.variant(...)
- @account.logo.download
+ @account.logo_blob.download
- @account.logo.purge
+ @account.logo_attachment.purge
EDIT: exclude :logo
parameter when saving/updating record (i.e. @account.update(account_params.except(:logo))
), or use a different parameter name.
I there !
I have the same issue with the Shopify App gem. The workaround is tenious. Any other solution?
Steps to reproduce
Updated rails gem from 5.1.4 to 5.2.0:
ran rails active_storage:install
ran rails db:migrate: 2 new tables created, active_storage_attachments and active_storage_blobs
Created config/storage.yml file:
local_test: service: Disk root: <%= Rails.root.join("tmp/storage") %>
Rails.application.configure do
Tell Active Storage which service to use by setting Rails.application.config.active_storage.service.
Because each environment will likely use a different service, it is recommended to do this on a per-environment basis.
config.active_storage.service = :local end
class Model < ActiveRecord::Base has_many_attached :documents
class Model < ActiveRecord::Base has_one_attached :avatar
Traceback (most recent call last): 84: from bin/rails:3:in'
52: from config.ru:in '
48: from config.ru:3:in '
/Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/activerecord-5.2.0/lib/active_record/dynamic_matchers.rb:22:in
<main>' 83: from bin/rails:3:in
load' 82: from /Users/username/Documents/repository-name/bin/spring:15:in<top (required)>' 81: from /Users/username/Documents/repository-name/bin/spring:15:in
require' 80: from /Users/username/.rvm/gems/ruby-2.5.1/gems/spring-2.0.2/lib/spring/binstub.rb:31:in<top (required)>' 79: from /Users/username/.rvm/gems/ruby-2.5.1/gems/spring-2.0.2/lib/spring/binstub.rb:31:in
load' 78: from /Users/username/.rvm/gems/ruby-2.5.1/gems/spring-2.0.2/bin/spring:49:in<top (required)>' 77: from /Users/username/.rvm/gems/ruby-2.5.1/gems/spring-2.0.2/lib/spring/client.rb:30:in
run' 76: from /Users/username/.rvm/gems/ruby-2.5.1/gems/spring-2.0.2/lib/spring/client/command.rb:7:incall' 75: from /Users/username/.rvm/gems/ruby-2.5.1/gems/spring-2.0.2/lib/spring/client/rails.rb:28:in
call' 74: from /Users/username/.rvm/gems/ruby-2.5.1/gems/spring-2.0.2/lib/spring/client/rails.rb:28:inload' 73: from /Users/username/Documents/repository-name/bin/rails:9:in
<top (required)>' 72: from /Users/username/Documents/repository-name/bin/rails:9:inrequire' 71: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.2.0/lib/rails/commands.rb:18:in
<top (required)>' 70: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.2.0/lib/rails/command.rb:46:ininvoke' 69: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.2.0/lib/rails/command/base.rb:65:in
perform' 68: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/thor-0.20.0/lib/thor.rb:387:indispatch' 67: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/thor-0.20.0/lib/thor/invocation.rb:126:in
invoke_command' 66: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/thor-0.20.0/lib/thor/command.rb:27:inrun' 65: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.2.0/lib/rails/commands/server/server_command.rb:142:in
perform' 64: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.2.0/lib/rails/commands/server/server_command.rb:142:intap' 63: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.2.0/lib/rails/commands/server/server_command.rb:147:in
block in perform' 62: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.2.0/lib/rails/commands/server/server_command.rb:51:instart' 61: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.2.0/lib/rails/commands/server/server_command.rb:89:in
log_to_stdout' 60: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/rack-2.0.5/lib/rack/server.rb:354:inwrapped_app' 59: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.2.0/lib/rails/commands/server/server_command.rb:27:in
app' 58: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/rack-2.0.5/lib/rack/server.rb:219:inapp' 57: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/rack-2.0.5/lib/rack/server.rb:319:in
build_app_and_options_from_config' 56: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/rack-2.0.5/lib/rack/builder.rb:40:inparse_file' 55: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/rack-2.0.5/lib/rack/builder.rb:49:in
new_from_string' 54: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/rack-2.0.5/lib/rack/builder.rb:49:ineval' 53: from config.ru:in
new' 51: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/rack-2.0.5/lib/rack/builder.rb:55:in
initialize' 50: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/rack-2.0.5/lib/rack/builder.rb:55:ininstance_eval' 49: from config.ru:3:in
block inrequire_relative' 47: from /Users/username/Documents/repository-name/config/environment.rb:5:in
<top (required)>' 46: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.2.0/lib/rails/application.rb:361:ininitialize!' 45: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.2.0/lib/rails/initializable.rb:60:in
run_initializers' 44: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/2.5.0/tsort.rb:205:intsort_each' 43: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/2.5.0/tsort.rb:226:in
tsort_each' 42: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/2.5.0/tsort.rb:347:ineach_strongly_connected_component' 41: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/2.5.0/tsort.rb:347:in
call' 40: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/2.5.0/tsort.rb:347:ineach' 39: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/2.5.0/tsort.rb:349:in
block in each_strongly_connected_component' 38: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/2.5.0/tsort.rb:415:ineach_strongly_connected_component_from' 37: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/2.5.0/tsort.rb:415:in
call' 36: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.2.0/lib/rails/initializable.rb:50:intsort_each_child' 35: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.2.0/lib/rails/initializable.rb:50:in
each' 34: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/2.5.0/tsort.rb:421:inblock in each_strongly_connected_component_from' 33: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/2.5.0/tsort.rb:431:in
each_strongly_connected_component_from' 32: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/2.5.0/tsort.rb:422:inblock (2 levels) in each_strongly_connected_component_from' 31: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/2.5.0/tsort.rb:350:in
block (2 levels) in each_strongly_connected_component' 30: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/2.5.0/tsort.rb:228:inblock in tsort_each' 29: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.2.0/lib/rails/initializable.rb:61:in
block in run_initializers' 28: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.2.0/lib/rails/initializable.rb:32:inrun' 27: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.2.0/lib/rails/initializable.rb:32:in
instance_exec' 26: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.2.0/lib/rails/engine.rb:613:inblock in <class:Engine>' 25: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.2.0/lib/rails/engine.rb:613:in
each' 24: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.2.0/lib/rails/engine.rb:614:inblock (2 levels) in <class:Engine>' 23: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.2.0/lib/rails/engine.rb:656:in
load_config_initializer' 22: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/activesupport-5.2.0/lib/active_support/notifications.rb:170:ininstrument' 21: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.2.0/lib/rails/engine.rb:657:in
block in load_config_initializer' 20: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/activesupport-5.2.0/lib/active_support/dependencies.rb:277:inload' 19: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/activesupport-5.2.0/lib/active_support/dependencies.rb:249:in
load_dependency' 18: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/activesupport-5.2.0/lib/active_support/dependencies.rb:277:inblock in load' 17: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/activesupport-5.2.0/lib/active_support/dependencies.rb:277:in
load' 16: from /Users/username/Documents/repository-name/config/initializers/constants.rb:4:in<top (required)>' 15: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/activesupport-5.2.0/lib/active_support/dependencies.rb:193:in
const_missing' 14: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/activesupport-5.2.0/lib/active_support/dependencies.rb:502:inload_missing_constant' 13: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/activesupport-5.2.0/lib/active_support/dependencies.rb:348:in
require_or_load' 12: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/activesupport-5.2.0/lib/active_support/dependencies.rb:37:inload_interlock' 11: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/activesupport-5.2.0/lib/active_support/dependencies/interlock.rb:13:in
loading' 10: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/activesupport-5.2.0/lib/active_support/concurrency/share_lock.rb:151:inexclusive' 9: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/activesupport-5.2.0/lib/active_support/dependencies/interlock.rb:14:in
block in loading' 8: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/activesupport-5.2.0/lib/active_support/dependencies.rb:37:inblock in load_interlock' 7: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/activesupport-5.2.0/lib/active_support/dependencies.rb:365:in
block in require_or_load' 6: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/activesupport-5.2.0/lib/active_support/dependencies.rb:467:inload_file' 5: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/activesupport-5.2.0/lib/active_support/dependencies.rb:653:in
new_constants_in' 4: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/activesupport-5.2.0/lib/active_support/dependencies.rb:468:inblock in load_file' 3: from /Users/username/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/activesupport-5.2.0/lib/active_support/dependencies.rb:468:in
load' 2: from /Users/username/Documents/repository-name/app/models/model.rb:1:in<top (required)>' 1: from /Users/username/Documents/repository-name/app/models/model.rb:2:in
method_missing': undefined method
has_one_attached' for Model (call 'Model.connection' to establish a connection):Class (NoMethodError)