Reputation: 487
I am back again with my ctrlpanel application.
I have it 100% working in development and went through the process to get it loaded up to Heroku and got the app up, gems installed. DB is there (mostly) but I have an issue even before the DB. I am getting an error dealing with devise_invitable that I DO NOT get in Development. To my surprise I do get the same error when I launch production on my laptop which was shocking to me to say the least as everything works perfect in development. So I know it isn't a Heroku issue which I am happy about at least I can reproduce it. The full error is below here but the line that specifically deals with the error is:
"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)"
I did some searching online (a lot of it actually) and the only thing I could find was a recommendation to copy the invitations_controller.rb file into a folder called users under the controllers folder, which I did try, I made a copy of it actually and I did also try moving it. Neither of which helped. This works properly in development. SO I started comparing the 2 environment files.
I got past it by changing these 2 entries:
config.cache_classes = false in production.rb
config.eager_load = false in production.rb
However I have seen postings everyplace that turning those 2 options off is very bad and it will effect the views somehow and sure enough my bootstrap is all caddywhompused which I can only assume is due to those 2 options being off. I'm sure someone else must have seen this before but I can't seem to find anything. I checked the devise_invitable docs, updated it to a v .02 higher (no effect).
The error is so long I am having a hard time find a good search term to get results.
I am confused as everything must be correct or it wouldn't be working right in development or I wouldn't think so? If there is any other file that needs to be seen please let me know and I will be happy to display it.
Thank you in advance for any help or advice you can offer.
Scott
Here is the error:
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)
Here is the routes.rb file:
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
Here is the invitations_controller.rb file:
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
Here is the application_controller.rb file:
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
Just in case here is also the application.rb file
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
Upvotes: 4
Views: 7547
Reputation: 487
I figured it out this morning.
I learned about a command called: rails zeitwerk:check --trace
When I ran it, it gave me this specific error: Hold on, I am eager loading the application. expected file app/controllers/users/invitations_controller.rb to define constant Users::InvitationsController
When I looked at my user model the main class declaration was written as: class User::InvitationsController < Devise::InvitationsController
The name of the model is user.rb so based on my experience with other languages I assumed the class name and the model name had to match, but I tried to rename it to:
class Users::InvitationsController < Devise::InvitationsController
I added the s in the Users::InvitationsController and then I ran the zeitwerk:check --trace again and it passed, I then tried to load the application into Production and what do you know it worked?
SO the SOLUTION in my case was in 2 parts:
1 Thank you @Scott Matthewman who informed me I needed to in fact MOVE the invitations_contoller.rb into a folder under controllers called users
/app/controllers/users.
2 I had to rename the User to Users in the class declaration (if that is the term in Ruby/Rails).
FROM:
User::InvitationsController < Devise::InvitationsController
TO:
Users::InvitationsController < Devise::InvitationsController
Upvotes: 9
Reputation: 10422
The recommendation to move invitations_controller.rb
into an app/controllers/users
folder is the correct one. That's the path that matches your route:
devise_for :users, controllers: { invitations: 'users/invitations' }
as well as your controller namespace:
class User::InvitationsController < Devise::InvitationsController
The key word is move here – if you left a copy of this file behind in app/controllers/invitations_controller.rb
, Zeitwerk might still have an issue trying to preload your code in production because of the namespace/file system mismatch.
If you move the file into its expected location and are still getting an error, then something else is going on and would be worth investigating further.
Upvotes: 1