2013-10-22 37 views
1

我正在爲Rails 4編寫一個需要向ApplicationController添加一些方法的gem,我想最好的方法是編寫一個rake任務來打開文件,插入我需要的方法,然後關閉它。爲了讓我的方法在類定義中,最好的方法是什麼?用rails 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,我也得到了以下錯誤:

undefined local variable or method `foo' for #<#:0x007ff350cd4ba0>

+0

你想讓你的寶石字面上編輯application_controller.rb?如果在運行時重新開放類(或者這不適用於你的gem做什麼?),在運行時擴展ApplicationController不是更好嗎?你可以嘗試從文件底部向上掃描,尋找一個'end' 'class ApplicationController'匹配 - 但我確信有可能被破壞的方法。 (你會嘗試你自己的解析。) – struthersneil

+0

是的,我正在尋找直接編輯它。我可能會誤解你'在運行時擴展'的意思,但是如果應用程序中存在一個具有相同名稱的控制器,那麼Rails會覆蓋這些控制器,所以我不能只將這些方法寫在我的引擎控制器中。 –

+0

考慮在一行中存在的類定義的可能性。或者一些尷尬但有效的情況,其中ApplicationController是通過調用Class.new()來定義的 – struthersneil

回答

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中定義並可供所有控制器使用 - 比方說,您希望您的gem用戶在逐控制器的基礎上「加入」。

class ApplicationController < ActionController::Base 
    with_rot_13 

    # and so on... 
end 

相反的include Rot13::ControllerMethods你可能稱之爲on_load塊內extend Rot13::ControllerOptIn到的ActionController::Base類級別添加with_rot_13方法,然後定義一個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 
+0

我已經更新了我的問題,包括我的最新試驗,而模塊正在加載,方法似乎不可用,無論我指定它們作爲實例或類方法。 –

+0

在控制器前加上您的呼叫,例如'controller.foo',如果你在視圖中。 – struthersneil

+0

錯誤中的類是#<#:0x007ff350cd4ba0> - 的線索 - 未定義的局部變量或方法foo - 如果對你的控制器調用foo,則會發生'#它不知何故) – struthersneil