为什么我的 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::Base
。 robot?
函数毫无疑问是一个实例方法。
我正在使用 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方法。
我的插件需要一些帮助。我想用一个方法扩展 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::Base
。 robot?
函数毫无疑问是一个实例方法。
我正在使用 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方法。