好的,我们一致认为更改主机应用程序的 application_controller.rb 不是可行的方法。让我们看看通过 gem 向 ApplicationController 类(实际上是 ActionController::Base)添加方法的不同方法。
我创建了一个非常简单的宝石。我希望它添加一个函数 rot13,这意味着任何控制器都可以调用rot13('something!')
get back 'fbzrguvat!'
。(在现实生活中,您会将其添加到String
...)
你可以像这样扩展ActionController::Base
:
class ActionController::Base
def rot13 str
a = 'a'.ord
z = 'z'.ord
str.unpack('c*').map { |x| (a..z).cover?(x) ? (((x - a) + 13) % 26) + a : x }.pack('c*')
end
end
现在在我的应用程序中,我可以rot13('ibvyn!')
在任何控制器内部调用voila!
添加一个模块并通过 Railtie 钩子将其包含在 ActionController::Base 中会更安全。所以让我们添加一个 Railtie。
我补充lib/rot13/railtie.rb
如下:
module Rot13
class Rot13Railtie < Rails::Railtie
initializer "rot_13_railtie.extend_action_controller" do
ActiveSupport.on_load :action_controller do
# At this point, self == ActionController::Base
include Rot13::ControllerMethods
end
end
end
end
现在lib/rot13.rb
看起来像这样:
require "rot13/version"
require "rot13/railtie.rb" if defined? Rails
module Rot13
module ControllerMethods
def rot13 str
a = 'a'.ord
z = 'z'.ord
str.unpack('c*').map { |x| (a..z).cover?(x) ? (((x - a) + 13) % 26) + a : x }.pack('c*')
end
end
end
这对于大多数用途来说都很好。
假设您不希望您的rot13
方法在所有控制器中定义ActionController::Base
并可供所有控制器使用——假设您希望 gem 的用户在逐个控制器的基础上“选择加入”,例如
class ApplicationController < ActionController::Base
with_rot_13
# and so on...
end
而不是include Rot13::ControllerMethods
您可以extend Rot13::ControllerOptIn
在该块中调用以在类级别on_load
添加一个方法,然后定义一个模块,如下所示:with_rot_13
ActionController::Base
ControllerOptIn
module Rot13
module ControllerMethods
# ...
end
module ControllerOptIn
def with_rot_13
include ControllerMethods
end
end
end
就是这样!
编辑:只是为了解决“为什么该方法在我的视图中不可见?”的附加问题-您的方法未定义为帮助程序,因此如果不controller
使用%p= controller.rot13 'blah'
. 幸运的是,您可以通过调用将其定义为助手helper_method
,例如
module ControllerOptIn
def with_rot_13
include ControllerMethods
helper_method :rot13
end
end
现在您可以执行此操作(注意:HAML):
%p= controller.rot13 'hello there!'
%p= rot13 'well how are ya?'
但是这里必须指定并不好helper_method :rot13
。你能直接从中挖出必要的符号Rot13::ControllerMethods
吗?当然,只要您确定这是您想要的:
module ControllerOptIn
def with_rot_13
include ControllerMethods
helper_method *ControllerMethods.instance_methods
end
end