1

私は ApplicationController にいくつかのメソッドを追加する必要がある Rails 4 用の gem を作成しています。そのための最善の方法は、rake タスクを作成してファイルを開き、必要なメソッドを挿入してから閉じることだと考えています。私のメソッドがクラス定義内にあるようにするための最良の方法は何ですか?

class ApplicationController < ActionController::Base

  def existing_methods
    foo
  end

  # insert my methods here

end

編集

以下の提案を試した後、役に立たなかったので、この投稿に従ってみましたが、最終的には次のことを試しました。

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次のエラーが表示されます。

#<#:0x007ff350cd4ba0> の未定義のローカル変数またはメソッド `foo'

4

1 に答える 1

3

わかりました。ホスト アプリの application_controller.rb を変更するのは適切ではないことに同意します。gem を介して ApplicationController クラス (実際には ActionController::Base) にメソッドを追加するさまざまな方法を見てみましょう。

非常にシンプルな宝石を作成しました。rot13 という 1 つの関数を追加したいのですが、これは、どのコントローラーでも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::ControllerOptInon_loadwith_rot_13ActionController::BaseControllerOptIn

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
于 2013-10-22T10:51:58.523 に答える