为什么我的 Rails 插件的功能在没有特别要求的情况下无法工作?

Why do functions from my Rails plugin not work without specifically requiring?

我的插件需要一些帮助。我想用一个方法扩展 ActiveRecord::Base,该方法初始化另一个可以在控制器中调用的方法。

看起来像这样:

class Article < ActiveRecord::Base
    robot_catch :title, :text
    ...
end

我用 robot_catch 方法扩展 ActiveRecord::Base class 的尝试如下所示。该函数将初始化变量中的指定属性(在本例中为 :title:text),并使用 class_eval 使 robot? 函数可供用户调用控制器:

module Plugin
    module Base
        extend ActiveSupport::Concern

        module ClassMethods
            def robot_catch(*attr)
                @@robot_params = attr

                self.class_eval do
                    def robot?(params_hash)
                        # Input is the params hash, and this function
                        # will check if the some hashed attributes in this hash
                        # correspond to the attribute values as expected,
                        # and return true or false.
                    end
                end
            end
        end
    end
end

ActiveRecord::Base.send :include, Plugin::Base

因此,在控制器中,可以这样做:

class ArticlesController < ApplicationController
    ...
    def create
        @article = Article.new(params[:article])

        if @article.robot? params
            # Do not save this in database, but render
            # the page as if it would have succeeded
            ...
        end
    end
end

我的问题是 robot_catch 是 class 方法是否正确。如上所示,此函数将在模型内部调用。我想知道我是否以正确的方式扩展了 ActiveRecord::Baserobot?函数毫无疑问是一个实例方法。

我正在使用 Rails 3.2.22,并且我将此插件作为 gem 安装在另一个我想使用此功能的项目中。

现在,只有当我在模型中专门 require gem 时它才有效。但是,我希望它的功能作为 ActiveRecord::Base 的一部分而不需要它,否则我必须 require 它在我想使用它的每个模型中,而不是特别是 。 gem 不应该在 Rails 启动时自动加载到项目中吗?

编辑: 也许回调(http://api.rubyonrails.org/classes/ActiveSupport/Callbacks/ClassMethods.html)可以解决这个问题,但我不知道如何使用它。好像有点晦涩。

首先,我建议您确保none of the many many built in Rails validators meet your needs

那么如果是这样的话,您真正想要的是自定义验证器。

构建自定义验证器并不像看起来那么简单,您将构建的基本 class 将具有以下结构:

class SpecialValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    # Fill this with your validation logic
    # Add to record.errors if validation fails
  end
end

那么在你的模型中:

class Article < ActiveRecord::Base
  validates :title, :text, special: true 
end

强烈建议确保您想要的尚未构建,很可能已经构建。然后使用resources like this or ruby guides resources继续走自定义验证器路线。

回答

我自己找到了解决方案。 Bundler 不会从我的项目使用的 gemspec 自动加载依赖项,因此我必须在我的应用程序的 lib/ 目录中的 engine.rb 文件中要求所有第三方 gem 才能加载 gem。现在一切正常。

第二:robot_catch方法是class方法。