Defect #26636

Rails 5: "Page not found" error when accessing a page of a plugin in production mode

Added by Go MAEDA 4 months ago. Updated 4 months ago.

Status:NewStart date:
Priority:NormalDue date:
Assignee:-% Done:

0%

Category:Plugin API
Target version:4.0.0
Resolution: Affected version:

Description

Steps to reproduce:

1. Create a test plugin.

bin/rails g redmine_plugin foo
bin/rails g redmine_plugin_controller foo foo index
echo 'get "foo", :to => "foo#index"' >> plugins/foo/config/routes.rb

2. Run Redmine in production mode

bin/rails s -e production

3. Open http://localhost/foo and you will see "Page not found" error. No problem in development mode.

production.log:

History

#1 Updated by Go MAEDA 4 months ago

  • Target version set to 4.0.0

#2 Updated by Go MAEDA 4 months ago

  • Description updated (diff)

#3 Updated by Akiko Takano 4 months ago

Hi, I'm triyng to port my plugins, from Redmine 3.4 to Redmine trunk (ver4.0, based on Rails5).
I managed to port my plugin to support Rails5, and it seems works fine under development / test environment.

But under production mode, I saw the same error.
When I try to access one of plugin's controller, error happened and the message such as "uninitialized constant xxxxxxxController” was recorded.

I personally think, it seems required files under plugin's directory are not loaded in production mode.
And also think this is because autoload definition is disabled for production mode in Rails 5 by default.

Ref. http://edgeguides.rubyonrails.org/upgrading_ruby_on_rails.html#autoloading-is-disabled-after-booting-in-the-production-environment

Here is my workaround and I am glad if they were helpful.

Workaround 1: Enabled autoload in production mode

$ hg diff config/application.rb 
diff -r 95623038cf82 config/application.rb
--- a/config/application.rb    Mon Jul 24 17:14:53 2017 +0000
+++ b/config/application.rb    Fri Aug 04 23:35:24 2017 +0900
@@ -12,6 +12,7 @@

     # Custom directories with classes and modules you want to be autoloadable.
     config.autoload_paths += %W(#{config.root}/lib)
+    config.enable_dependency_loading = true

     # Only load the plugins named here, in the order given (default is alphabetical).
     # :all can be used as a placeholder for all plugins not explicitly named.

Workaround 2: Add plugin's directory to eager_load_paths at lib/redmine/plugin.rb

When application boots in production then the application loads all constants found in all directories listed in eager_load_paths.

$ hg diff lib/redmine/plugin.rb 
diff -r 95623038cf82 lib/redmine/plugin.rb
--- a/lib/redmine/plugin.rb    Mon Jul 24 17:14:53 2017 +0000
+++ b/lib/redmine/plugin.rb    Fri Aug 04 23:38:31 2017 +0900
@@ -93,6 +93,7 @@
       # Adds the app/{controllers,helpers,models} directories of the plugin to the autoload path
       Dir.glob File.expand_path(File.join(p.directory, 'app', '{controllers,helpers,models}')) do |dir|
         ActiveSupport::Dependencies.autoload_paths += [dir]
+        Rails.application.config.eager_load_paths += [dir] if Rails.env == 'production'
       end

       # Defines plugin setting if present

I personally prefer the second way.

Also available in: Atom PDF