You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Devise脚手架生成器source_root重复设置问题求助

解决Devise脚手架生成器source_root冲突问题

问题背景

构建Devise脚手架生成器时,取消注释source_root=File.expand_path("../../templates/controllers", __FILE__)后测试失败,控制器动作报错:

Could not find "confirmations_controller.rb" in any of your source paths. Your current source paths are:
/home/jackparsons210/devise/lib/generators/active_record/templates
.system temporary path is world-writable: /tmp
/tmp is world-writable: /tmp
[repeated thrice]

无法重复设置source_root,询问是否必须通过File命令手动处理模板。

解决方案

不需要手动处理文件,有两种更优雅的方式解决source_root冲突问题:

方法1:调用template时使用模板绝对路径

直接在template方法中传入模板文件的绝对路径,无需修改全局source_root,避免和原有ActiveRecord模板路径冲突:

def create_controllers
  # 获取控制器模板的根目录绝对路径
  controller_templates_root = File.expand_path("../../templates/controllers", __FILE__)
  @scope_prefix = table_name.blank? ? '' : (table_name.camelize + '::')
  
  CONTROLLERS.each do |name|
    template File.join(controller_templates_root, "#{name}_controller.rb"),
             "app/controllers/#{table_name}/#{name}_controller.rb"
  end
end

方法2:临时切换source_root后恢复

在create_controllers方法内先保存原有source_root,临时切换到控制器模板路径,完成模板生成后再恢复原路径,不影响其他方法使用原source_root:

def create_controllers
  # 保存原有source_root
  original_source_root = self.class.source_root
  # 临时切换到控制器模板路径
  self.class.source_root = File.expand_path("../../templates/controllers", __FILE__)
  
  @scope_prefix = table_name.blank? ? '' : (table_name.camelize + '::')
  CONTROLLERS.each do |name|
    template "#{name}_controller.rb",
             "app/controllers/#{table_name}/#{name}_controller.rb"
  end
  
  # 恢复原有source_root
  self.class.source_root = original_source_root
end

问题原因

source_root是类级别的配置,直接全局修改会覆盖掉生成器原本的ActiveRecord模板路径(../templates),导致依赖该路径的方法(比如copy_devise_migration)无法找到迁移模板,同时控制器模板路径也没正确生效,所以出现找不到控制器模板的错误。上面两种方法都避免了全局修改source_root,既保证控制器模板能被找到,也不影响原有功能。

修改后的完整生成器代码片段

替换原create_controllers方法即可,其他代码保持不变:

# frozen_string_literal: true

require 'rails/generators/active_record'
require 'generators/devise/orm_helpers'
require "generators/devise/controllers_generator.rb"
module ActiveRecord
  module Generators
    class ScaffoldGenerator < ActiveRecord::Generators::Base
      argument :attributes, type: :array, default: [], banner: "field:type field:type"

      class_option :primary_key_type, type: :string, desc: "The type for primary key"

      include Devise::Generators::OrmHelpers
      source_root File.expand_path("../templates", __FILE__)
    
      # ... 其他原有方法保持不变 ...
    
      CONTROLLERS = %w(confirmations passwords registrations sessions unlocks omniauth_callbacks).freeze

      # 使用方法1的实现
      def create_controllers
        controller_templates_root = File.expand_path("../../templates/controllers", __FILE__)
        @scope_prefix = table_name.blank? ? '' : (table_name.camelize + '::')
        
        CONTROLLERS.each do |name|
          template File.join(controller_templates_root, "#{name}_controller.rb"),
                   "app/controllers/#{table_name}/#{name}_controller.rb"
        end
      end
    end
  end
end

内容的提问来源于stack exchange,提问作者jack parsons

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 05:40:39