Extending controllers of a Rails 3 Engine in the main app

后端 未结 7 909
执念已碎
执念已碎 2020-11-30 02:52

I am using a Rails engine as a gem in my app. The engine has PostsController with a number of methods and I would like to extend the controller logic in my main

相关标签:
7条回答
  • 2020-11-30 03:03

    If you do not want patch active support to change the load order as suggested in Rails engines extending functionality, you can make use of a rack middleware for authentication. If authentication is done as part of every controller action, this approach might save you lot of code and time.

    0 讨论(0)
  • 2020-11-30 03:07

    You can use Ruby's send() method to inject your code into the controller at the time the engine is created...

    # lib/cool_engine/engine.rb
    
    module CoolEngine
      class Engine < ::Rails::Engine
    
        isolate_namespace CoolEngine
    
        initializer "cool_engine.load_helpers" do |app|
          # You can inject magic into all your controllers...
          ActionController::Base.send :include, CoolEngine::ActionControllerExtensions
          ActionController::Base.send :include, CoolEngine::FooBar
    
          # ...or add special sauce to models...
          ActiveRecord::Base.send :include, CoolEngine::ActiveRecordExtensions
          ActiveRecord::Base.send :include, CoolEngine::MoreStuff
    
          # ...even provide a base set of helpers
          ApplicationHelper.send :include, CoolEngine::Helpers
        end
      end
    end
    

    This method spares you from having to redefine the controller inheritance within your main app.

    0 讨论(0)
  • 2020-11-30 03:11

    @cowboycoded method 2 in conjunction with require_dependency and config.reload_plugins worked for me on Rails 3.2.2 / Ruby 1.9.

    Here is the code: https://stackoverflow.com/a/9790497/22237

    0 讨论(0)
  • 2020-11-30 03:18

    Method 1

    Here is what I put in my Rails 3 app in application.rb after require 'rails/all' (let me know if it is a bad place to put it)

    require 'active_support/dependencies'
    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.to_s + '/app')
          relative_name = file_name.gsub(Rails.root.to_s, '')
          #@engine_paths ||= Rails::Application.railties.engines.collect{|engine| engine.config.root.to_s }
          #EDIT: above line gives deprecation notice in Rails 3 (although it works in Rails 2), causing error in test env.  Change to:
          @engine_paths ||= YourAppName::Application.railties.engines.collect{|engine| engine.config.root.to_s }
          @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
    

    For a while this didn't work raising

    TypeError in PostsController#index
    
    superclass mismatch for class PostsController
    

    but that was due to a mistyped class definition class PostsController < ActionController::Base which should be class PostsController < ApplicationController

    Method 2

    If you do not want to do this for all engine controllers etc., you can load the engine's controller before the definition in the main app

    require PostsEngine::Engine.config.root + 'app' + 'controllers' + 'posts_controller'
    
    class PostsController < ApplicationController
      # extended methods
    end
    
    0 讨论(0)
  • 2020-11-30 03:22

    I've created a gem based on the code from Andrius and Andrei above. Instead of copying around that code, just require the mixable_engines gem. Only works with rails 3 right now.

    https://github.com/asee/mixable_engines

    https://rubygems.org/gems/mixable_engines

    @Andrei and @Artrius: I've credited you in the license file, let me know if you want your real name or some other credit.

    0 讨论(0)
  • 2020-11-30 03:25

    Why not just inherit from the Engine's controller class in your application (and point your routes at the new child controllers)? Sounds conceptually similar to the way that you extend built-in Devise controllers.

    0 讨论(0)
提交回复
热议问题