使用rails rake任务插入方法的最佳方法

时间:2013-10-22 01:09:46

标签: ruby-on-rails gem ruby-on-rails-4

我正在为Rails 4编写一个需要向ApplicationController添加一些方法的gem,我认为最好的方法是编写一个rake任务来打开文件,插入我需要的方法,然后关闭它。最好的方法是什么,以便我的方法在类定义中?

class ApplicationController < ActionController::Base

  def existing_methods
    foo
  end

  # insert my methods here

end

修改

在尝试下面的建议后,但无济于事,我尝试了this post,最后尝试了以下内容:

LIB / my_engine.rb

require "my_engine/engine"
require "my_engine/controller_methods"

module MyEngine
end

LIB / my_engine / controller_methods.rb

module MyEngine
  module ControllerMethods
    extend ActiveSupport::Concern

    def foo
      "foo"
    end

  end
end
ActiveRecord::Base.send(:include, MyEngine::ControllerMethods)

运行应用程序时,我的application.slim包含行= foo,我收到以下错误:

  

#&lt;#:0x007ff350cd4ba0&gt;

的未定义局部变量或方法`foo'

1 个答案:

答案 0 :(得分:3)

好的,我们同意改变主机应用的application_controller.rb是不可取的。让我们看一下通过gem将方法添加到ApplicationController类(实际上是ActionController :: Base)的不同方法。

我创造了一个非常简单的宝石。我希望它添加一个函数rot13,这意味着任何控制器都可以调用rot13('something!')来获取'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中定义并且可供所有控制人使用 - 让我们说您想要用户宝石来选择加入&#39;在逐个控制器的基础上,例如

class ApplicationController < ActionController::Base
  with_rot_13

  # and so on...
end

您可以在include Rot13::ControllerMethods块中调用extend Rot13::ControllerOptIn而不是on_load,而是在with_rot_13的类级添加ActionController::Base方法,然后定义{ {1}}模块如下:

ControllerOptIn

那就是它!

修改:只是为了解决“为什么我的视图中无法看到该方法”的其他问题?&#39; - 您的方法未定义为帮助程序,因此在视图中不会自动显示,而不会使用module Rot13 module ControllerMethods # ... end module ControllerOptIn def with_rot_13 include ControllerMethods end end end 加上后缀,例如controller。幸运的是,您可以通过调用%p= controller.rot13 'blah'将其定义为帮助者,例如

helper_method

现在你可以这样做(注:HAML):

module ControllerOptIn
  def with_rot_13
    include ControllerMethods
    helper_method :rot13
  end
end

但是在这里指定%p= controller.rot13 'hello there!' %p= rot13 'well how are ya?' 并不是很好。你能直接从helper_method :rot13挖出必要的符号吗?当然,只要你确定它是你想要的:

Rot13::ControllerMethods