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

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"

用户使用方式

  1. 在Rails项目的Gemfile中添加:
gem "my_gem", path: "../path/to/your/gem" # 本地开发用,发布后换成rubygems地址
  1. (可选)在config/application.rb中配置:
config.my_gem.enabled = true # 默认开启,可设为false临时禁用
config.my_gem.excluded_controllers = ["Admin::DashboardController"] # 排除特定控制器
  1. 启动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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 02:10:51