Rails7部署Heroku后Stimulus Flash消息功能失效 报JS资产路由错误
Rails7+Tailwind部署Heroku后Stimulus Flash功能失效排查
问题现象
- 技术栈版本:Rails 7.0.2.4、Ruby 3.1.2p20、Tailwind CSS
- 功能逻辑:通过Stimulus实现Flash消息3秒自动消失、点击按钮手动关闭功能,本地开发环境运行完全正常,部署到Heroku后功能全部失效
- Heroku日志核心报错:
2022-06-02T07:51:13.858354+00:00 app[web.1]: F, [2022-06-02T07:51:13.858304 #4] FATAL -- : [a7811503-f91a-4d6e-9a5d-978744f7129b] 2022-06-02T07:51:13.858355+00:00 app[web.1]: [a7811503-f91a-4d6e-9a5d-978744f7129b] ActionController::RoutingError (No route matches [GET] "/assets/controllers/flash_controller.js"):
报错本质:生产环境无法找到编译后的flash_controller.js资产文件,Stimulus控制器未正常加载注册
现有相关代码
1. 全局布局文件 app/views/layouts/application.html.erb
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1"> <%= csrf_meta_tags %> <%= csp_meta_tag %> <%= stylesheet_link_tag "tailwind", "inter-font", "data-turbo-track": "reload" %> <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %> <%= javascript_importmap_tags %> <%= render 'layouts/shim' %> <title><%= page_title(yield(:title)) %></title> </head> <body class="pb-420 box-border"> <main> <%= render 'shared/navbar' %> <%= render partial: 'shared/flash' %> <div class="w-full"> <%= yield %> <%= render 'shared/footer' %> </div> </main> </body> </html>
2. Flash消息渲染模板
<% flash.each do |key, value| %> <div data-controller="flash" class="flex items-center fixed top-5 right-5 <%= css_class_for_flash(key) %> py-3 px-5 rounded-lg"> <div class="mr-4"><%= value %></div> <button type="button" data-action="flash#dismiss"> <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" /> </svg> </button> </div> <% end %>
3. Stimulus Flash控制器 app/javascript/controllers/flash_controller.js
import { Controller } from "@hotwired/stimulus" export default class extends Controller { connect() { setTimeout(() => { this.dismiss(); }, 3000); } dismiss() { this.element.remove(); } }
4. Stimulus控制器注册文件
当前文件存放路径:app/javascript/controller/index.js(注意目录名为单数形式)
import { application } from "./application" import FlashController from "./flash_controller.js" application.register("flash", FlashController)
修复方案
按优先级依次排查修复:
- 修正目录命名错误
当前Stimulus控制器注册入口index.js放在了单数命名的app/javascript/controller/目录下,而Rails + Stimulus默认的资产扫描、控制器加载路径是复数命名的app/javascript/controllers/目录。本地开发环境资产加载规则宽松,会递归扫描javascript目录下的所有js文件,所以功能正常;但生产环境资产预编译只会加载标准路径下的入口文件,导致注册逻辑根本没被执行,浏览器只能直接请求裸的控制器文件路径触发404。
操作:把app/javascript/controller/index.js移动到app/javascript/controllers/index.js路径下,和flash_controller.js、application.js放在同一目录。 - 更新importmap映射配置
因为之前入口文件路径错误,importmap没有正确收录自定义Stimulus控制器的资产路径,本地项目根目录执行以下命令,自动把所有自定义控制器的路径写入importmap配置:
执行完成后检查bin/importmap pin app/javascript/controllers/**/*.jsconfig/importmap.rb文件,确认存在flash_controller相关的pin配置即可。 - 重新部署验证
把上述修改提交到Git仓库,重新推送到Heroku触发部署,部署日志中确认出现Asset precompilation completed相关提示,代表资产已经正确编译。部署完成后访问页面,Flash消息的自动消失、手动关闭功能即可恢复正常,不会再出现js文件404的报错。
内容的提问来源于stack exchange,提问作者mojaomi
相关产品推荐
相关产品推荐

