on_file_autoloaded':期望文件 invitations_controller.rb 定义常量 InvitationsController,但没有(Zeitwerk::NameError)

on_file_autoloaded': expected file invitations_controller.rb to define constant InvitationsController, but didn't (Zeitwerk::NameError)

我带着我的 ctrlpanel 应用程序又回来了。

我将它 100% 用于开发,并完成了将其加载到 Heroku 并启动应用程序、安装 gems 的过程。 DB 在那里(大部分),但我什至在 DB 之前就遇到了问题。我在处理 devise_invitable 时遇到错误,我在开发中没有得到。令我惊讶的是,当我在我的笔记本电脑上启动生产时,我确实遇到了同样的错误,这至少让我感到震惊,因为一切都在开发中完美运行。所以我知道这不是 Heroku 问题,我很高兴至少我可以重现它。完整错误在此处,但专门处理该错误的行是:

"C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/zeitwerk-2.4.2/lib/zeitwerk/loader/callbacks.rb:18:in `on_file_autoloaded': expected file D:/rails/ctrlpanel/app/controllers/invitations_controller.rb to define constant InvitationsController, but didn't (Zeitwerk::NameError)C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/zeitwerk-2.4.2/lib/zeitwerk/loader/callbacks.rb:18:in `on_file_autoloaded': expected file D:/rails/ctrlpanel/app/controllers/invitations_controller.rb to define constant InvitationsController, but didn't (Zeitwerk::NameError)"

我在网上做了一些搜索(实际上搜索了很多),我唯一能找到的是建议将 invitations_controller.rb 文件复制到 controllers 文件夹下名为 users 的文件夹中,我确实尝试过,我实际上复制了它,我也尝试移动它。两者都没有帮助。这在开发中正常工作。所以我开始比较这两个环境文件。

我通过更改这 2 个条目来克服它:

config.cache_classes = false in production.rb
config.eager_load = false in production.rb

但是我看到到处都有帖子说关闭这两个选项是非常糟糕的,它会以某种方式影响视图并且确实我的 bootstrap 是所有 caddywhompused 我只能假设是由于这两个选项正在关闭。我敢肯定其他人以前一定见过这个,但我似乎找不到任何东西。我检查了 devise_invitable 文档,将其更新为更高的 v .02(无效)。
错误太长,我很难找到一个好的搜索词来获得结果。

我很困惑,因为一切都必须正确,否则它不会在开发中正常工作,或者我不这么认为?如果还有任何其他文件需要查看,请告诉我,我很乐意展示它。

提前感谢您提供的任何帮助或建议。

斯科特

这里是错误:

scottm@RED-IT-LAP-0001 MINGW64 /d/rails/ctrlpanel (master)
$ rails server -e production
=> Booting Puma
=> Rails 6.1.3.2 application starting in production
=> Run `bin/rails server --help` for more startup options
Exiting
Traceback (most recent call last):
        67: from bin/rails:14:in `<main>'
        66: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/bootsnap-1.7.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:31:in `require'
        65: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/bootsnap-1.7.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require_with_bootsnap_lfi'
        64: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/bootsnap-1.7.5/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register'
        63: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/bootsnap-1.7.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `block in require_with_bootsnap_lfi'
        62: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/bootsnap-1.7.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `require'
        61: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/railties-6.1.3.2/lib/rails/commands.rb:18:in `<main>'
        60: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/railties-6.1.3.2/lib/rails/command.rb:50:in `invoke'
        59: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/railties-6.1.3.2/lib/rails/command/base.rb:69:in `perform'
        58: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/thor-1.1.0/lib/thor.rb:392:in `dispatch'
        57: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/thor-1.1.0/lib/thor/invocation.rb:127:in `invoke_command'
        56: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/thor-1.1.0/lib/thor/command.rb:27:in `run'
        55: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/railties-6.1.3.2/lib/rails/commands/server/server_command.rb:135:in `perform'
        54: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/railties-6.1.3.2/lib/rails/commands/server/server_command.rb:135:in `tap'
        53: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/railties-6.1.3.2/lib/rails/commands/server/server_command.rb:144:in `block in perform'
        52: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/railties-6.1.3.2/lib/rails/commands/server/server_command.rb:39:in `start'
        51: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/rack-2.2.3/lib/rack/server.rb:311:in `start'
        50: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/rack-2.2.3/lib/rack/server.rb:379:in `handle_profiling'
        49: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/rack-2.2.3/lib/rack/server.rb:312:in `block in start'
        48: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/rack-2.2.3/lib/rack/server.rb:422:in `wrapped_app'
        47: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/rack-2.2.3/lib/rack/server.rb:249:in `app'
        46: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/rack-2.2.3/lib/rack/server.rb:349:in `build_app_and_options_from_config'
        45: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/rack-2.2.3/lib/rack/builder.rb:66:in `parse_file'
        44: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/rack-2.2.3/lib/rack/builder.rb:105:in `load_file'
        43: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/rack-2.2.3/lib/rack/builder.rb:116:in `new_from_string'
        42: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/rack-2.2.3/lib/rack/builder.rb:116:in `eval'
        41: from config.ru:3:in `block in <main>'
        40: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/activesupport-6.1.3.2/lib/active_support/dependencies.rb:332:in `require'
        39: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/activesupport-6.1.3.2/lib/active_support/dependencies.rb:299:in `load_dependency'
        38: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/activesupport-6.1.3.2/lib/active_support/dependencies.rb:332:in `block in require'
        37: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/zeitwerk-2.4.2/lib/zeitwerk/kernel.rb:34:in `require'
        36: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/bootsnap-1.7.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:31:in `require'
        35: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/bootsnap-1.7.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require_with_bootsnap_lfi'
        34: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/bootsnap-1.7.5/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register'
        33: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/bootsnap-1.7.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `block in require_with_bootsnap_lfi'
        32: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/bootsnap-1.7.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `require'
        31: from D:/rails/ctrlpanel/config/environment.rb:5:in `<main>'
        30: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/railties-6.1.3.2/lib/rails/railtie.rb:207:in `method_missing'
        29: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/railties-6.1.3.2/lib/rails/railtie.rb:207:in `public_send'
        28: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/railties-6.1.3.2/lib/rails/application.rb:384:in `initialize!'
        27: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/railties-6.1.3.2/lib/rails/initializable.rb:60:in `run_initializers'
        26: from C:/Ruby27-x64/lib/ruby/2.7.0/tsort.rb:205:in `tsort_each'
        25: from C:/Ruby27-x64/lib/ruby/2.7.0/tsort.rb:226:in `tsort_each'
        24: from C:/Ruby27-x64/lib/ruby/2.7.0/tsort.rb:347:in `each_strongly_connected_component'
        23: from C:/Ruby27-x64/lib/ruby/2.7.0/tsort.rb:347:in `call'
        22: from C:/Ruby27-x64/lib/ruby/2.7.0/tsort.rb:347:in `each'
        21: from C:/Ruby27-x64/lib/ruby/2.7.0/tsort.rb:349:in `block in each_strongly_connected_component'
        20: from C:/Ruby27-x64/lib/ruby/2.7.0/tsort.rb:431:in `each_strongly_connected_component_from'
        19: from C:/Ruby27-x64/lib/ruby/2.7.0/tsort.rb:350:in `block (2 levels) in each_strongly_connected_component'
        18: from C:/Ruby27-x64/lib/ruby/2.7.0/tsort.rb:228:in `block in tsort_each'
        17: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/railties-6.1.3.2/lib/rails/initializable.rb:61:in `block in run_initializers'
        16: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/railties-6.1.3.2/lib/rails/initializable.rb:32:in `run'
        15: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/railties-6.1.3.2/lib/rails/initializable.rb:32:in `instance_exec'
        14: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/railties-6.1.3.2/lib/rails/application/finisher.rb:133:in `block in <module:Finisher>'
        13: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/zeitwerk-2.4.2/lib/zeitwerk/loader.rb:508:in `eager_load_all'
        12: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/zeitwerk-2.4.2/lib/zeitwerk/loader.rb:508:in `each'
        11: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/zeitwerk-2.4.2/lib/zeitwerk/loader.rb:393:in `eager_load'
        10: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/zeitwerk-2.4.2/lib/zeitwerk/loader.rb:393:in `synchronize'
         9: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/zeitwerk-2.4.2/lib/zeitwerk/loader.rb:404:in `block in eager_load'
         8: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/zeitwerk-2.4.2/lib/zeitwerk/loader.rb:725:in `ls'
         7: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/zeitwerk-2.4.2/lib/zeitwerk/loader.rb:725:in `foreach'
         6: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/zeitwerk-2.4.2/lib/zeitwerk/loader.rb:733:in `block in ls'
         5: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/zeitwerk-2.4.2/lib/zeitwerk/loader.rb:409:in `block (2 levels) in eager_load'
         4: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/zeitwerk-2.4.2/lib/zeitwerk/loader.rb:409:in `const_get'
         3: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/zeitwerk-2.4.2/lib/zeitwerk/kernel.rb:26:in `require'
         2: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/zeitwerk-2.4.2/lib/zeitwerk/kernel.rb:26:in `tap'
         1: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/zeitwerk-2.4.2/lib/zeitwerk/kernel.rb:27:in `block in require'
C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/zeitwerk-2.4.2/lib/zeitwerk/loader/callbacks.rb:18:in `on_file_autoloaded': expected file D:/rails/ctrlpanel/app/controllers/invitations_controller.rb to define constant InvitationsController, but didn't (Zeitwerk::NameError)

这是 routes.rb 文件:

Catalog::Application.routes.draw do  

 resources :redline_filters
  resources :certifications
  resources :routes do
    resources :waypoints, only: [:show, :destroy]
  end

  resources :dealerships do
    collection do
      get 'index_public'
      get 'deduplicate'
    end
    resources :visits
  end

  resources :items do
    resources :variants, except: :index do
      resources :snapshots
    end
  end

  resources :crosses do
    collection do
      get 'index_public'
    end
  end
  

  root to: 'static_pages#home'

  devise_for :users, controllers: { invitations: 'users/invitations' }

  
  resources :locations, :categories, :gfe_users, :trips, :vendors, :work_orders
  resources :attachments, only: [:destroy]

  get '/gfe_reporting', to: 'gfe_users#reporting'

  resources :users do
    get 'toggle_suspend'
  end

  resources :charges do
    collection do
      post 'import'
    end
  end


  resources :products do
    match 'submit' => 'products#submit', via: [:get, :post]
    match 'publish' => 'products#publish', via: [:get, :post]
    match 'in_progress' => 'products#in_progress', via: [:get, :post]
    # collection { post :search, to: 'products#index' } ## ransack crap.
  end

  resources :devices do
    resources :trips
  end

  # match "/home" => 'static_pages#home'
  match "/catalog" => 'static_pages#catalog', via: [:get, :post]
  match "product/:name" => "products#index", via: [:get, :post]
  get "static_pages/products"
  get "static_pages/catalog"
  get "static_pages/help"
  get "static_pages/roi"
  get "/roi", to: "static_pages#roi"


  match 'device_lookup', to: 'devices#lookup', via: [:get, :post]
  match 'device_first_avaiable_serial', to: 'devices#first_available_serial', via: [:get, :post]
  match 'device_battery_is_dead' => 'devices#update_status_to_dead_battery', via: [:get, :post]
  match 'device_is_missing' => 'devices#is_missing', via: [:get, :post]
  match 'device_has_water_damage' => 'devices#update_status_to_water_damage', via: [:get, :post]
  match 'device_is_rma' => 'devices#update_status_to_rma', via: [:get, :post]
  match 'device_is_healthy' => 'devices#is_healthy', via: [:get, :post]
  match 'pending_trip' => 'trips#pending_trip', via: [:get, :post]
  match 'complete_trip' => 'trips#complete_trip', via: [:get, :post]

  # The priority is based upon order of creation:
  # first created -> highest priority.

  # Sample of regular route:
  #   match 'products/:id' => 'catalog#view'
  # Keep in mind you can assign values other than :controller and :action

  # Sample of named route:
  #   match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase
  # This route can be invoked with purchase_url(:id => product.id)

  # Sample resource route (maps HTTP verbs to controller actions automatically):
  #   resources :products

  # Sample resource route with options:
  #   resources :products do
  #     member do
  #       get 'short'
  #       post 'toggle'
  #     end
  #
  #     collection do
  #       get 'sold'
  #     end
  #   end

  # Sample resource route with sub-resources:
  #   resources :products do
  #     resources :comments, :sales
  #     resource :seller
  #   end

  # Sample resource route with more complex sub-resources
  #   resources :products do
  #     resources :comments
  #     resources :sales do
  #       get 'recent', :on => :collection
  #     end
  #   end

  # Sample resource route within a namespace:
  #   namespace :admin do
  #     # Directs /admin/products/* to Admin::ProductsController
  #     # (app/controllers/admin/products_controller.rb)
  #     resources :products
  #   end

  # You can have the root of your site routed with "root"
  # just remember to delete public/index.html.
  # root :to => 'welcome#index'

  # See how all your routes lay out with "rake routes"

  # This is a legacy wild controller route that's not recommended for RESTful applications.
  # Note: This route will make all actions in every controller accessible via GET requests.
  # match ':controller(/:action(/:id))(.:format)'
end

这是 invitations_controller.rb 文件:

class User::InvitationsController < Devise::InvitationsController
  def new
    if cannot?(:invite, User)
      raise CanCan::AccessDenied
    else
      super
    end
  end

  def create
    if cannot?(:invite, User)
      raise CanCan::AccessDenied
    else
      self.resource = resource_class.invite!(resource_params, current_inviter)

      unless resource.role.present?
        resource.role = "creator"
        resource.save
      end

      if resource.errors.empty?
        set_flash_message :notice, :send_instructions, :email => self.resource.email
        respond_with resource, :location => after_invite_path_for(resource)
      else
        respond_with_navigational(resource) { render :new }
      end
    end
  end

  private
  def resource_params
    params.permit(user: [:name, :email, :invitation_token, :location_id])[:user]
  end
end

这是 application_controller.rb 文件:

class ApplicationController < ActionController::Base
   
  protect_from_forgery prepend: true

  #before_filter :configure_permitted_parameters, if: :devise_controller?
  before_action :configure_permitted_parameters, if: :devise_controller?

  #before_filter :authenticate_user!
  before_action :authenticate_user!

  #check_authorization :unless => :devise_controller?
  after_action :unless => :devise_controller?
 
  before_action :set_paper_trail_whodunnit

  rescue_from CanCan::AccessDenied do |exception|
    redirect_to root_url, :alert => exception.message
  end

  protected

  def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:sign_up, keys: [ :first_name, :last_name, :email] )
    devise_parameter_sanitizer.permit(:account_update, keys: [ :first_name, :last_name, :phone, :email ] )
    devise_parameter_sanitizer.permit(:invite, keys: [ :name, :location_id ] )
  end
end

以防万一这里还有application.rb文件

require_relative "boot"

require "rails/all"

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

module Catalog #Ctrlpanel
  class Application < Rails::Application

    # Initialize configuration defaults for originally generated Rails version.
    config.load_defaults 6.1

    config.before_configuration do
      env_file = File.join(Rails.root, 'config', 'local_env.yml')
      YAML.load(File.open(env_file)).each do |key, value|
        ENV[key.to_s] = value
      end if File.exists?(env_file)
    end

  config.autoload_paths += %W(#{config.root}/lib)

  config.encoding = "utf-8"
  config.time_zone = 'Pacific Time (US & Canada)'
  config.active_record.default_timezone = :local

  config.filter_parameters += [:password]

  config.active_support.escape_html_entities_in_json = true

  # Enable pdf.css precompiling for wicked_pdf
  config.assets.precompile += %w( pdf.css print.css awesome-bootstrap-checkbox.css jquery.dataTables.min.css )

  # Force Heroku to not access the DB or load models when precompiling your assets.
  config.assets.initialize_on_precompile = false

  # Use SQL instead of Active Record's schema dumper when creating the database.
  # This is necessary if your schema can't be completely dumped by the schema dumper,
  # like if you have constraints or database-specific column types
  # config.active_record.schema_format = :sql

  # Enforce whitelist mode for mass assignment.
  # This will create an empty whitelist of attributes available for mass-assignment for all models
  # in your app. As such, your models will need to explicitly whitelist or blacklist accessible
  # parameters by using an attr_accessible or attr_protected declaration.
  
  # This breaks the application 3/30/2021 Scott Milella
  config.active_record.whitelist_attributes = true

  # 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'

    # Configuration for the application, engines, and railties goes here.
    #
    # These settings can be overridden in specific environments using the files
    # in config/environments, which are processed later.
    #
    # config.time_zone = "Central Time (US & Canada)"
    # config.eager_load_paths << Rails.root.join("extras")

  # No Method Error message 3/31/2021 Scott Milella
  #config.active_record.raise_in_transactional_callbacks = true

  end
end

invitations_controller.rb 移动到 app/controllers/users 文件夹的建议是正确的。这是与您的路线匹配的路径:

devise_for :users, controllers: { invitations: 'users/invitations' }

以及您的控制器命名空间:

class User::InvitationsController < Devise::InvitationsController

这里的关键字是 move – 如果您在 app/controllers/invitations_controller.rb 中留下了此文件的副本,Zeitwerk 在尝试预加载您的代码时可能仍然存在问题生产因为 namespace/file 系统不匹配。

如果您将文件移至其预期位置,但仍然出现错误,则说明发生了其他问题,值得进一步调查。

我今天早上弄明白了。

我了解到一个名为: rails zeitwerk:check --trace

当我 运行 它时,它给了我这个特定的错误: 稍等,我急于加载应用程序。 预期文件 app/controllers/users/invitations_controller.rb 定义常量 Users::InvitationsController

当我查看我的用户模型时,主要的 class 声明写成: class User::InvitationsController < Devise::InvitationsController

模型的名称是 user.rb 所以根据我使用其他语言的经验,我假设 class 名称和模型名称必须匹配,但我尝试将其重命名为: class Users::InvitationsController < Devise::InvitationsController
我在 Users::InvitationsController 中添加了 s,然后我再次 运行 zeitwerk:check --trace 并且它通过了,然后我尝试将应用程序加载到 Production 中,你知道它有效吗?

所以我的解决方案分为两部分: 1 谢谢@Scott Matthewman,他告诉我实际上我需要将 invitations_contoller.rb 移动到名为用户的控制器下的文件夹中 /app/controllers/users.
2 我必须在 class 声明中将用户重命名为用户(如果这是 Ruby/Rails 中的术语)。 从: User::InvitationsController < Devise::InvitationsController 到: Users::InvitationsController < Devise::InvitationsController