ruby-on-rails - 在主应用程序中扩展 Rails 3 引擎的 Controller

标签 ruby-on-rails ruby-on-rails-3 rubygems rails-engines

我在我的应用程序中使用 Rails 引擎作为 gem。引擎有PostsController使用多种方法,我想在我的主应用程序中扩展 Controller 逻辑,例如添加一些方法。如果我只是创建 PostsController在主应用程序中,则未加载引擎的 Controller 。

问题中提出了一个解决方案Rails engines extending functionality基于更改 ActiveSupport::Dependencies#require_or_load
这是唯一/正确的方法吗?如果是,我把那段代码放在哪里?

编辑1:

这是代码suggested by Andrius用于 Rails 2.x

module ActiveSupport::Dependencies
  alias_method :require_or_load_without_multiple, :require_or_load
  def require_or_load(file_name, const_path = nil)
    if file_name.starts_with?(RAILS_ROOT + '/app')
      relative_name = file_name.gsub(RAILS_ROOT, '')
      @engine_paths ||= Rails::Initializer.new(Rails.configuration).plugin_loader.engines.collect {|plugin| plugin.directory }
      @engine_paths.each do |path|
        engine_file = File.join(path, relative_name)
        require_or_load_without_multiple(engine_file, const_path) if File.file?(engine_file)
      end
    end
    require_or_load_without_multiple(file_name, const_path)
  end
end

最佳答案

按照设计,Rails::Engine 中的类应该限定为引擎。这样他们就不会通过意外踩踏主应用程序或其他引擎中加载的所有代码来引入奇怪的错误。 Monkeypatching ActiveSupport::Dependencies 来全面混合引擎是一个非常糟糕的解决方法。

只需使用 Rails::Railtie 即可。它们具有所有相同的功能,但与引擎的范围不同。您可以访问整个 rails 应用程序堆栈(包括引擎)。这是一种更外科手术的方法。

module MyModule

  module SomeModelExtensions
    # Called when this module is included on the given class.
    def self.included(base)
      base.send(:include, InstanceMethods)
      base.extend(ClassMethods)
    end

    module ClassMethods
      def some_new_class_method
        # do stuff...
      end
    end

    module InstanceMethods
      def some_new_instance_method
        # do stuff...
      end
    end

  end

  module SomeControllerExtensions
    def self.included(base)
      base.send(:include, InstanceMethods)
      base.alias_method_chain :new, :my_module
    end

    module InstanceMethods
      # override the 'new' method
      def new_with_my_module
        # do stuff
      end
    end
  end

  class Railtie < ::Rails::Railtie

    # The block you pass to this method will run for every request in
    # development mode, but only once in production.
    config.to_prepare do
      SomeModel.send(:include, MyModule::SomeModelExtensions)
      SomeController.send(:include, MyModule::SomeControllerExtensions)
    end

  end

end

就文件布局而言,railties 看起来与引擎完全一样。

进一步阅读:Extending Rails 3 with Railties

如果您仍然感到困惑,请查看这个具有完整实现的 git 项目:https://github.com/jamezilla/bcms_pubcookie

关于ruby-on-rails - 在主应用程序中扩展 Rails 3 引擎的 Controller ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5045068/

相关文章:

ruby-on-rails-3 - 如何确保用户名不会与现有路由冲突?

ruby-on-rails - 找不到 PostgreSQL 客户端库 (libpq)

ruby-on-rails - Rails 自定义验证器仅在控制台中不起作用

css - Twitter Bootstrap + Rails,如何整合修改?

ruby-on-rails - 无法在延迟工作中点击混合面板?

ruby-on-rails - CSS:将元素宽度限制为偶数

macos - 安装 pg gem 不安装 postgres macOS

ruby - 您如何访问 VCR 盒式磁带中的数据进行测试?

javascript - 通过 JavaScript 函数调用时,Rails 部分未呈现

mysql - Ruby on Rails 安装、Windows10 上的 Ubuntu #<Mysql2::Error: Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)>