Rails 装饰器,覆盖 Rails 引擎

3

我正在编写一些装饰器来覆盖一个Rails引擎,如这里所述。我试图向引擎中的一个类添加一个简单的方法,以下是我的代码:

# app/decorators/models/my_engine/user_decorator.rb

MyEngine::User.class_eval do
  def self.find_by_name_or_mis_id str
    where("CONCAT(#{table_name}.firstname, ' ', #{table_name}.surname) LIKE CONCAT('%', :s, '%') OR mis_id = :s", { s: str })
  end
end

我的应用找不到这个方法,在Rails控制台里我试图测试它:

# rails c
MyEngine::User.find_by_name_or_mis_id "John"
NoMethodError: undefined method `find_by_name_or_mis_id' for #<Class:0x007fcb85a45580>

我可以在控制台中执行require '/models/my_engine/user_decorator'来使其工作,为什么Rails没有识别我的装饰器?

4个回答

6

经过一番搜索,发现它们似乎没有自动加载。所需的是从forem repo中借鉴(在将其提取到this gem之前):

# MyEngine
# lib/my_engine/engine.rb

module MyEngine
  class Engine < ::Rails::Engine
    isolate_namespace MyEngine

    config.to_prepare do
      Dir.glob(Rails.root + "app/decorators/**/*_decorator*.rb").each do |c|
        require_dependency(c)
      end
    end
  end
end

我会在文档中提出一个问题单,以便他们可以包含这些信息,因为他们详细介绍了装饰器,但没有解释如何实际加载它们(假设所有这些都已经为您处理好了)。
更新:我确实提出了问题单,并相应地更新了指南。

嗨,Mike。谢谢这个,真的很有帮助!你确定指南已经更新了吗?我刚刚遇到了同样的问题,但没有在这里找到它的提及:http://guides.rubyonrails.org/engines.html#overriding-models-and-controllers - PJC
5
顺便问一下,我假设这段代码放在引擎本身里面是对的吗?这不有点奇怪吗?我的意思是引擎不应该需要知道那个,是吗? - PJC
3
为了避免在路径中硬编码斜杠:Rails.root.join('app', 'decorators', '**', '*_decorator*.rb') - Sarah Vessels

2
config.to_prepare do
  # Load application's model / class decorators
  Dir.glob(File.join(File.dirname(__FILE__), "../app/**/*_decorator*.rb")) do |c|
    Rails.configuration.cache_classes ? require(c) : load(c)
  end
end

1

抱歉打扰了一个旧问题。我在使用decorators gem时遇到了一些问题。一个替代方案是activesupport-decorators


0

如果您需要一种灵活的替代方案,同时又不带有内置装饰器require_dependency功能的Rails引擎,请考虑镜像要覆盖的类的文件路径,并使用require_dependency在自定义之前要求原始类。

这种技术不使用装饰器。相反,它重新打开具有相同名称的文件中的类:

# File: app/models/my_engine/user.rb

# Load the original class definition from the engine:
require_dependency "#{MyEngine::Engine.root}/app/models/my_engine/user"

# Open class to modify it:
module MyEngine
  class User
    def self.find_by_name_or_mis_id(str)
      where("CONCAT(#{table_name}.firstname, ' ', #{table_name}.surname) LIKE CONCAT('%', :s, '%') OR mis_id = :s", { s: str })
    end
  end
end

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接