"Unable to autoload constant User" 在开发中更改代码时出错

"Unable to autoload constant User" error when changed code in development

我的 rails 应用程序有问题。从 Rails 3 更新到 4 后。 当我在开发模式下启动服务器后浏览页面时,一切都很好。

但是在一次代码更改(甚至添加 space)之后,每个页面请求都会显示以下错误。

Unable to autoload constant User, expected /path/to/my/rails-app/app/models/user.rb to define it

文件就在那里并定义了 class:

class User < ActiveRecord::Base
  …

我在 application.rb 中用 config.autoload_pathsconfig.eager_load_paths 尝试了很多东西,但没有成功。 停用 spring 也无济于事。

开发一个应用程序并在每次更改后都必须重新启动服务器似乎是 90 年代。

$ rails -v
Rails 4.2.4
$ ruby -v
ruby 2.1.7p400 (2015-08-18 revision 51632) [x86_64-linux]

一些相关配置:

development.rb

MyApp::Application.configure do
    # Settings specified here will take precedence over those in config/application.rb

  # In the development environment your application's code is reloaded on
  # every request.  This slows down response time but is perfect for development
  # since you don't have to restart the webserver when you make code changes.
  config.cache_classes = false

  # Do not eager load code on boot. This avoids loading your whole application
  # just for the purpose of running a single test. If you are using a tool that
  # preloads Rails for running tests, you may have to set it to true.
  config.eager_load = false

  # Show full error reports and disable caching
  config.consider_all_requests_local       = true
  config.action_controller.perform_caching = false

  # Don't care if the mailer can't send
  config.action_mailer.raise_delivery_errors = false

  # Print deprecation notices to the Rails logger
  config.active_support.deprecation = :log

  # Only use best-standards-support built into browsers
  config.action_dispatch.best_standards_support = :builtin

  # Do not compress assets
  config.assets.compress = false

  # Expands the lines which load the assets
  config.assets.debug = true

  config.action_mailer.delivery_method = :test
  config.action_mailer.default_url_options = {
    host: 'localhost',
    port: 3000
  }

end

application.rb

module Serviceportal
  class Application < Rails::Application    
    # Enable the asset pipeline
    config.assets.enabled = true

    # Version of your assets, change this if you want to expire all your assets
    config.assets.version = '1.0'

    [… some asset precompile stuff …]

    # Configure the default encoding used in templates for Ruby 1.9.
    config.encoding = 'utf-8'

    # Custom directories with classes and modules you want to be autoloadable.
    config.autoload_paths += Dir["#{config.root}/app/mailers",
        "#{config.root}/app/controllers/concerns",
        "#{config.root}/app/models/concerns",
        "#{config.root}/app/decorators/concerns",
        "#{config.root}/lib",
        "#{config.root}/lib/shared"
    ]
    config.eager_load_paths += Dir["#{config.root}/app/mailers",
        "#{config.root}/app/controllers/concerns",
        "#{config.root}/app/models/concerns",
        "#{config.root}/app/decorators/concerns",
        "#{config.root}/lib",
        "#{config.root}/lib/shared"]

    # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
    # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
    config.time_zone = 'Berlin'

    # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
    # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
    config.i18n.default_locale = :de

    [… some SQL and active support stuff …]

    config.action_controller.include_all_helpers = false

    config.action_controller.action_on_unpermitted_parameters = :raise

    # Do not swallow errors in after_commit/after_rollback callbacks.
    config.active_record.raise_in_transactional_callbacks = true
  end
end

编辑:错误大部分出现在lib/auth/user_proxy.rb在以下功能中。也许这有助于缩小可能原因的范围。

def self.usertype_allowed?(type)
  [ User, TempCustomer ].include? type.classify.safe_constantize rescue false
end

编辑 2: 将编辑 1 中的 class 名称字符串化有帮助(感谢@Benjamin Sinclaire)。但只会导致下一个错误。我也可以避免使用 classes。但是在 app/controllers/concerns/security.rb 中的以下错误没有什么可以改变的?

Unable to autoload constant User, expected /path/to/my/rails-app/app/models/user.rb to define it

代码:

def set_current_user
  User.current = current_user
end

当前用户保存在线程中(代码来自 /path/to/my/rails-app/app/models/user.rb

def self.current
  Thread.current['current_user']
end

def self.current=(user)
  Thread.current['current_user'] = user
end

再说一遍:它在开发中服务器重启后工作,直到我在某处更改一些代码。

1 看看有没有多级的class或者模块的声明一行一行的改成多行声明的

而不是

class Parent::Sub::Child
end

module Parent
  module Sub
    class Child
    end
  end
end

2 检查您的模型关联定义,并确保您从不使用常量。请改用字符串。

而不是

belongs_to :manager, class_name: User

belongs_to :manager, class_name: 'User'

3 刚刚看到您的编辑。你能这样重构吗?

# I assume `type` is a string or such, so we can compare classes
# names instead of constants, and get rid of `safe_constantize`
def self.usertype_allowed?(type)
  ['User', 'TempCustomer'].include? type.classify rescue false
end

4 序列化线程存储中的活动记录对象不是一个好主意。改为存储用户 ID,如下所示:

def set_current_user
  User.current = current_user.id
end

def self.current
  Thread.current['current_user_id']
end

def self.current=(user_id)
  Thread.current['current_user_id'] = user_id
end

您不需要在自动加载/预加载路径中包含 app/models/concernsapp/controllers/concerns,因为它们默认包含在 Rails 4: https://signalvnoise.com/posts/3372-put-chubby-models-on-a-diet-with-concerns

还要确保将您的问题定义为模块,扩展 ActiveSupport::Concern 并使用适当的文件名

#taggable.rb
module Taggable
  extend ActiveSupport::Concern
end

您的问题的另一个原因可能是 app/decorators/concernsliblib/shared 中的某些模块/ class 正在使用 User class 尚未加载或它的某些依赖项未加载,因此请尝试在这些文件的顶部添加 require_relative path_to_user.rb

-----编辑------

尝试在 lib/auth/user_proxy.rb

的顶部添加
require_dependency 'app/models/user'

这样你就可以消除自动加载 User class 时的任何歧义,并且你不会乱用 Rails 自动加载,请在此处查看更多信息:http://guides.rubyonrails.org/autoloading_and_reloading_constants.html#require-dependency , http://guides.rubyonrails.org/autoloading_and_reloading_constants.html#common-gotchas

同样的问题,但在带有名称空间的引擎中。在代码更改/自动加载之前,生产或开发中没有问题。

解决方案是

  1. 检查双重定义(有 none)
  2. 检查模块嵌套是否严格遵循rails文件系统中的约定。

我在 myengine/app/myns/subns/obj.rb 下有 myns 但是 myns 被忽略了,因为它在 的应用程序文件夹,因此将 myns 文件夹移动到 子文件夹 myengine/app/lib/myns 解决了问题。

注意: rails 错误消息非常明确地说明了模块嵌套(同时仍然指向文件系统中错误的 .rb 文件),因此请仔细查看错误。错误是 'Unable to autoload constant subns/obj.rb in .../myns/subns/obj.rb'。 Rails 在这种情况下建议不正确的文件位置(存在)具有误导性。

在 Rails/Ruby 更新期间,我抽空调查了这个问题并最终找到了原因。

用户 class 多年来一直使用 unloadable。这导致了自 Rails 4 以来的问题。现在我删除了它,之后没有发现任何问题。