Ruby Gem开发:无需修改控制器代码,让Gem方法自动作用于所有控制器方法
实现Ruby Gem自动在所有控制器方法执行时调用指定方法
核心思路
利用Rails的控制器回调机制和Railtie扩展规范,在Gem加载时自动将回调注入到所有ActionController基类中,无需用户修改任何控制器代码。
Gem实现步骤
1. 基础目录结构
my_gem/ ├── lib/ │ ├── my_gem/ │ │ ├── railtie.rb # 处理Rails集成的核心文件 │ │ └── core.rb # 存放业务逻辑方法 │ └── my_gem.rb # Gem入口文件 └── my_gem.gemspec
2. 入口文件(lib/my_gem.rb)
负责加载核心模块和Rails集成逻辑:
require "my_gem/core" require "my_gem/railtie" if defined?(Rails)
3. 核心业务逻辑(lib/my_gem/core.rb)
定义需要自动调用的方法:
module MyGem # 可接收控制器实例作为参数,以便获取请求上下文(可选) def self.put_text(controller = nil) # 替换为你的实际业务逻辑 puts "MyGem.put_text triggered for action: #{controller&.action_name}" if controller # 示例:记录日志 Rails.logger.info "[MyGem] Executed alongside controller action" end end
4. Rails集成核心(lib/my_gem/railtie.rb)
通过Railtie注入全局控制器回调,这是实现自动调用的关键:
module MyGem class Railtie < Rails::Railtie # 提供可配置项,让用户灵活控制行为 config.my_gem = ActiveSupport::OrderedOptions.new config.my_gem.enabled = true config.my_gem.excluded_controllers = [] initializer "my_gem.inject_controller_callback" do |app| # 若用户禁用则跳过注入 next unless app.config.my_gem.enabled # 在ActionController基类加载时注入回调 ActiveSupport.on_load(:action_controller) do # 选择合适的回调类型:before/after/around_action # 这里用after_action确保控制器方法执行完成后触发 after_action :call_my_gem_put_text, unless: -> { excluded_from_my_gem? } private def call_my_gem_put_text # 将当前控制器实例传入,便于获取上下文 MyGem.put_text(self) end def excluded_from_my_gem? app.config.my_gem.excluded_controllers.include?(self.class.name) end end end end end
5. Gemspec配置
确保声明Rails依赖:
# my_gem.gemspec spec.name = "my_gem" spec.version = "0.1.0" spec.summary = "Automatically triggers MyGem.put_text on all controller actions" spec.authors = ["Your Name"] spec.files = Dir["lib/**/*"] spec.require_path = "lib" # 声明Rails版本依赖(根据实际支持范围调整) spec.add_runtime_dependency "rails", ">= 6.0"
用户使用方式
- 在Rails项目的Gemfile中添加:
gem "my_gem", path: "../path/to/your/gem" # 本地开发用,发布后换成rubygems地址
- (可选)在
config/application.rb中配置:
config.my_gem.enabled = true # 默认开启,可设为false临时禁用 config.my_gem.excluded_controllers = ["Admin::DashboardController"] # 排除特定控制器
- 启动Rails服务,所有控制器方法执行时会自动调用
MyGem.put_text。
回调类型说明
根据需求选择不同的回调:
before_action:控制器方法执行前触发after_action:控制器方法执行后触发around_action:包裹控制器方法,可在执行前后都处理(示例如下):
# 在railtie的ActionController回调中替换为: around_action :wrap_with_my_gem private def wrap_with_my_gem MyGem.put_text(self) # 执行前触发 yield # 执行控制器方法 MyGem.put_text(self) # 执行后触发 end
内容的提问来源于stack exchange,提问作者Subi
相关产品推荐
相关产品推荐

