【问题标题】:Delegate class in main app to class in rails engine将主应用程序中的类委托给 Rails 引擎中的类
【发布时间】:2012-12-07 00:33:02
【问题描述】:

我有一个独立的 Rails 引擎:Admin

在那个引擎中,我通过 GUI 创建 Sites

在引擎中:

module Admin
  class Site < ActiveRecord::Base
  end
end

在主应用程序中,我从引擎的Site 继承,以便在根级别将其用作常量:

class Site < Admin::Site
end

我这样做是因为在主应用程序的模型、控制器和测试中耦合 Admin::Site 感觉不对。但我猜这种方法有一些缺点,我也猜想有人可能会争辩说耦合是一样的。

我怎样才能以比继承更好的方式委派它?

我是否应该重组我的代码并将Site 类放在主应用程序和引擎都可以使用的gem 中?我真正想要的是引擎类的接口,以减少入口点,从而减少耦合。

旁注,我总共有 3-4 个此类驻留在引擎中,但在主应用程序中使用。

编辑:

也许我应该这样包装它:

class Site 
  def initialize(args = {})
    @klass = Admin::Site.new(args)    
  end

  def method_missing(method_name, *args, &block)
    @klass.send(method_name, *args, &block)
  end
end

当然,那我也可以缩小Site的界面,只在主应用程序中包含我需要的Admin::Site

【问题讨论】:

    标签: ruby-on-rails rails-engines loose-coupling


    【解决方案1】:

    想到了两种可能的解决方案,
    1) ActiveSupport::Conern
    2)公开课

    鉴于您已将这 3-4 个模型/控制器隔离在一个引擎中,一种方法是利用 ActiveSupport::Concern 将引擎的功能明确包含在 MainApp 中。

    更多信息,Rails Docs on ActiveSupport::Concern

    ActiveSupport::关注示例:

    # Rails Engine
    module SomeEngine
      module SomeController
    
        extend ActiveSupprt::Concern
    
        included do
          before_filter :some_before_filter
        end
    
        # regular instance methods
        def index 
          ...
        end
    
        protected
        def some_before_filter
          ....
        end
    
      end
    end    
    
    # MainApp
    class SomeController < BaseController
      include SomeEngine::SomeController
    
      # rest of MainApp logic
    end
    

    另一种常见的方法是在运行时重写 Ruby 类方法(“开放类”)Spree 通过在 MainApp 中为 Engine 模型/控制器类实现“装饰器”模式来做到这一点。

    更多信息在这里,Spree's implementation of Decorators

    “#class_eval do”示例,

    # in MainApp
    SomeEngine::SomeController.class_eval do
      # logic added in the MainApp
    end
    

    我也想看看 RailsConf 关于 RailsEngnes 的演讲,
    http://confreaks.com/videos/863-railsconf2012-rails-engines-patterns

    【讨论】:

    • 感谢 westyfresh,虽然这两种解决方案都很棒并且可以解决不同的问题,但我不喜欢它们中的任何一个。所有 3-4 个类都在整个引擎以及主应用程序中的多个位置使用,不是作为模块而是作为类,我当然可以将它们移动到模块中,然后将该模块包含在引擎和应用程序中,但是对我来说真的没有意义。我也不想在主应用程序中添加逻辑我只想在多个地方使用这些类并希望有一个入口点,但也许我应该直接引用它Admin::Site。跨度>
    • 只是为了更好地理解您:您想要 MainApp 中的“Admin::Site”功能但使用“Site”命名空间?如果是这样, include 似乎是最接近的解决方案。但如果你不想那样,那我不知道还有其他选择。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-05-07
    • 2012-11-14
    • 1970-01-01
    • 1970-01-01
    • 2014-05-25
    • 2015-01-08
    • 1970-01-01
    相关资源
    最近更新 更多