将主应用程序中的类委托给rails引擎中的类

时间:2012-12-07 00:33:03

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

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

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

发动机中的

module Admin
  class Site < ActiveRecord::Base
  end
end

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

class Site < Admin::Site
end

我这样做是因为在主app的模型,控制器和测试中将Admin::Site结合起来感觉不对。但我想这种方法有一些缺点,我猜也可能会认为耦合是相同的。

如何以比继承更好的方式委托这个?

OR

我应该重构我的代码并将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所需的内容。

1 个答案:

答案 0 :(得分:1)

我想到了两种可能的解决方案,
1)ActiveSupport :: Conern
2)开放分级

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

此处有更多信息,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类方法(“open classing”)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谈论aout RailsEngnes,
http://confreaks.com/videos/863-railsconf2012-rails-engines-patterns