简体   繁体   English

将主应用中的类委托给Rails引擎中的类

[英]Delegate class in main app to class in rails engine

I have an isolated Rails Engine: Admin . 我有一个隔离的Rails Engine: Admin

In that Engine I create Sites through a GUI. 在该引擎中,我通过GUI创建Sites

in Engine: 在引擎中:

module Admin
  class Site < ActiveRecord::Base
  end
end

In main app I inherit from the engine's Site in order to use it as a constant at the root level: 在主应用程序中,我从引擎的Site继承,以便在根级别将其用作常量:

class Site < Admin::Site
end

I do this because it feels wrong to couple the Admin::Site in models, controllers and tests of the main app. 我这样做是因为在主应用程序的模型,控制器和测试中将Admin::Site耦合在一起感觉不对。 But I guess there's some downsides to this approach and I also guess one could argue that the coupling is the same. 但是我猜想这种方法有一些弊端,我也可能会认为耦合是相同的。

How can I delegate this in a better way than inheritance? 我该如何以比继承更好的方式委派这个?

OR 要么

Should I restructure my code and maybe put the Site class in a gem that both the main app and the Engine can use? 我应该重组代码,或者将Site类放到主应用程序和引擎都可以使用的gem中吗? What I would really like is an interface to the engine's class to reduce the entry points, and thus the coupling. 我真正想要的是引擎类的接口,以减少入口点,从而减少耦合。

Sidenote, I have a total of 3-4 of these classes that resides in the engine but is used in the main app. 旁注,我总共有3-4个此类驻留在引擎中,但在主应用程序中使用。

EDIT: 编辑:

Maybe I should just wrap it like this: 也许我应该像这样包装它:

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

Of course, then I could also narrow the interface of Site to only include what I need from Admin::Site in the main app. 当然,那么我还可以缩小Site的界面,使其仅包含主应用程序中Admin::Site所需的内容。

Two possible solutions come to mind, 我想到了两种可能的解决方案,
1) ActiveSupport::Conern 1)ActiveSupport :: Conern
2) Open Classing 2)公开课

Given that you have isolated these 3-4 Models/Controllers in an Engine, one approach is to leverage the ActiveSupport::Concern to explicitly include your Engine's functionality in the MainApp. 鉴于您已经在引擎中隔离了这3-4个模型/控制器,一种方法是利用ActiveSupport :: ConcernMainApp中明确包含引擎的功能。

More info here, Rails Docs on ActiveSupport::Concern 此处的更多信息, ActiveSupport :: Concern上的Rails Docs

ActiveSupport::Concern example: 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

Another common approach is to rewrite a Ruby class methods at run time ("open classing") . 另一种常见的方法是在运行时重写Ruby类方法(“开放类”) Spree does this by implementing the "decorator" pattern on for Engine model/contrller classes in the MainApp. Spree通过在MainApp中为Engine模型/控制器类实现“装饰器”模式来实现此目的。

More info here, Spree's implementation of Decorators 更多信息在这里, Spree的Decorators的实现

"#class_eval do" example, “ #class_eval做”示例,

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

I would also check out this RailsConf talk aout RailsEngnes, 我还将在RailsEngnes上查看有关RailsConf的演讲,
http://confreaks.com/videos/863-railsconf2012-rails-engines-patterns http://confreaks.com/videos/863-railsconf2012-rails-engines-patterns

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM