如何将NAMED SCOPES(或其他声明)添加到已安装gem的模型(例如我们的Forem gem)?

时间:2012-09-24 04:37:36

标签: ruby-on-rails-3.2

环境

ruby​​ 1.9.3p194(2012-04-20修订版35410)[x86_64-darwin10.8.0]; Rails 3.2.6; OSX 10.6.8;设计(2.0.4); forem-redcarpet(1.0.0)

目的

我们需要在Forem安装(gem)中部署额外的订单控制。可能,我们还想要声明更多的模型属性;而且,我们也会这样做:

  1. 将命名范围附加到基础Forem模型;
  2. 通过覆盖基础模型
  3. 问题

    我们如何做

2 个答案:

答案 0 :(得分:1)

答案 - 如何解决装饰品中的异常执行问题

一位同事将我的请求指向现有的Forem文档( Forem: Extending Classes ),很好地回答这个问题,除了以下内容,非常可能的例外:

我之前没有回应的一个原因是,尝试遵循推荐的模式最初并没有成功,因为一些底层代码(少数例外)引用了模型类而没有预先设置它们属于Forem引擎。因此,起初,似乎这条路线根本不起作用;而且,(我仍然不确定所有后果是什么),因此似乎有必要在表格中覆盖基础方法(不以“Forem ::”为前缀)和修订后的引用,“Forem :: ModelName”(与“ModelName”相对)。

正如Github的Forem文档页面所示:

“所有Forem的业务逻辑(模型,控制器,帮助器等)都可以使用标准的Ruby习语轻松扩展/覆盖,以满足您的确切需求。

在您的应用程序或扩展程序中包含此类更改的标准做法是创建目录应用程序/装饰器。将文件放在相关的 app / decorators / models app / decorators / controllers 目录, _decorator 附加到原始类名。“

换句话说,要在控制器进程中分配更多接口值,您必须将一个装饰器添加到Ruby将找到的相应目录并覆盖基础进程:

来自原始Forem源的控制器驻留为/ forem / app / 控制器 / forem / admin / groups_controller.rb ,因此被/ your_project_name / app /覆盖装饰器 / 控制器 / forem / admin / groups_controller_decorator.rb

在下面的代码片段中(来自这个文件),你会定期调用“index_original”,将原始索引方法别名为“index_original”:

Forem::Admin::GroupsController.class_eval do
alias_method :index_original, :index unless method_defined?(:index_original)

def index
    @h_title_of_page = t('h_title2_forum_admin_groups_index')
    @h_description2 = t('h_description2_forums')

    index_original 
    end

然而,这不起作用,因为Forem控制器的基础索引方法进行以下分配:

@groups = Group.all

当你在装饰器中调用index_original时,对“Group.all”的调用会因错误而出现错误,显然是因为如果没有前缀表明它属于Forem模块,则无法识别祖先:

@groups = Forem::Group.all

因此,要在装饰器中修复此问题,您必须采取以下方法(注释#index_original以指示必须替换它的内容):

def index
    @h_title_of_page = t('h_title2_forum_admin_groups_index')
    @h_description2 = t('h_description2_forums')

    # index_original
        @groups = Forem::Group.all # @groups = Group.all ERROR 
    end

请注意,语句“@groups = Forem :: Group.all”是祖先索引方法的唯一声明;因此将固定语句带入装饰器是将整个方法代码带入您自己的装饰器中。这修复了异常执行,只是因为祖先索引方法的完全覆盖足以消除对Forem ::之前没有开始的模型的任何进一步调用。 如果对基础类的任何进一步调用都没有开头,那么这些方法同样必须加入装饰器。

所以,为了解决你自己(依赖)项目中的每一个这样的潜在失常,你必须从Github下载Forem源,并研究你必须使用的基础方法别名参考他们自己的模型,有/没有用“Forem ::”作为前缀:

  1. 如果您正在调用的Forem进程调用的所有被调用模型都是前置,那么我的努力表明您可以别名调用原始方法(例如index_original) )。
  2. 但是,如果在装饰者调用的过程中对Forem模型的任何底层调用都不以“Forem ::”为前提,我的努力表明你必须将所有底层方法的代码都输入到你的装饰者(如上所述)。
  3. 希望将来,Ruby要么能识别这样的引用,要么/或者Forem作者会在他们的内部开头提到他们的引用(即使代码显然应该运行得很好,否则 in Forem发展环境)。

答案 1 :(得分:0)

嗯......我建议1.(诚然,因为我确实有答案;-))

将其放入autoload_paths:

extend_it.rb

require 'active_support/concern'

module ExtendIt
  extend ActiveSupport::Concern

  included do
    scope :extension_scope, where(:name => "Mr. X")
  end

  module ClassMethods
  end
end      

在初始化程序中有类似的东西:

extend_it.rb

AnyClass.send :include, ExtendIt

当然AnyClass是您的目标类之一。可在此处找到更多阅读材料:http://api.rubyonrails.org/classes/ActiveSupport/Concern.html